Unity centring camera on transform and limiting camera movement to map - c#

I'm learning unity and I'm recreating a game of mine I wrote in XNA in unity.
I have the main camera script to adjust itself to the position of the player transform, but I want it to be limited to the map bounds.
That gives me 2 problems:
1) Add the script portion that limits the camera movement to the bounds of the map
2) Get the actual map bounds from the mass of prefabs that are thrown on the map.
This is another post of mine regarding collision with the walls that doesn't work (if you'd like, go in the post, as I would love to have some help with the collision problem as well)
This is how the camera looks with size 4.5 when I roughly centered it on the map:
This is how the camera looks with size 4.5 when it's simply showing some part of the map and is out of it
When I lower the camera size to 3, it looks roughly like so:
There are 3 things to do based on that:
1) Limit the camera size not to be able to be bigger than the map width
2) Limit the camera movement not to be able to move outside of the map
2.1) To be able to do (2) I need to get the map bounds.
To generate the map, I use the scripts from the tutorial specified in my other post, and changed to my needs:
using System.Collections.Generic;
using UnityEngine;
namespace Assets.Scripts
{
internal enum BlockPosition
{
None = -1,
Top = 0,
Bottom,
Left,
Right,
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
public class BoardManager : MonoBehaviour
{
private const int BORDER_COL = -1;
public int columns = 15;
public int rows = 15;
// Up, Down, Left, Right, TopLeft, TopRight, BottomLeft, BottomRight
public GameObject[] wallTiles;
public GameObject[] floorTiles;
private readonly List<Vector3> floorPositions = new List<Vector3>();
private Transform boardHolder;
private Transform floorHolder;
private Transform wallsHolder;
private void InitializeFloorPositionsList()
{
floorPositions.Clear();
for (int i = 0; i < columns; ++i)
{
for (int j = 0; j < rows; ++j)
{
floorPositions.Add(new Vector3(i, j, 0f));
}
}
}
/// <summary>
/// Gets the BlockPosition based on where on the wall grid the block is
/// </summary>
/// <param name="row">Row of the block</param>
/// <param name="col">Column of the block</param>
/// <returns>BlockPosition representing the position of the wall, or BlockPosition.None if it's a center block(a floor)</returns>
private BlockPosition GetBlockIndex(int row, int col)
{
///////////
// 1 2 3 //
// 4 5 6 // Number represents position in map
// 7 8 9 //
///////////
if (row == BORDER_COL)
{
if (col == BORDER_COL)
return BlockPosition.BottomLeft; // 7
if (col == columns)
return BlockPosition.BottomRight; // 9
return BlockPosition.Bottom; // 8
}
if (row == rows)
{
if (col == BORDER_COL)
return BlockPosition.TopLeft; // 1
if (col == columns)
return BlockPosition.TopRight; // 3
return BlockPosition.Top; // 2
}
if (col == BORDER_COL)
return BlockPosition.Left; // 4
if (col == columns)
return BlockPosition.Right; // 6
return BlockPosition.None; // 5
}
private void SetUpWalls()
{
boardHolder = new GameObject("Board").transform;
floorHolder = new GameObject("Floors").transform;
floorHolder.parent = boardHolder;
wallsHolder = new GameObject("Walls").transform;
wallsHolder.parent = boardHolder;
for (int col = BORDER_COL; col < columns + 1; col++)
{
for (int row = BORDER_COL; row < rows + 1; row++)
{
BlockPosition pos = GetBlockIndex(row, col);
if (pos == BlockPosition.None) continue;
GameObject toInstantiate = wallTiles[(int)pos];
GameObject instance =
Instantiate(toInstantiate, new Vector3(col, row, 0f), Quaternion.identity) as GameObject;
instance.transform.parent = wallsHolder;
}
}
}
private Vector3 RandomPosition()
{
int randomIndex = Random.Range(0, floorPositions.Count);
Vector3 position = floorPositions[randomIndex];
floorPositions.RemoveAt(randomIndex);
return position;
}
private void LayoutObjectsAtRandom(GameObject[] objects, int amount, Transform parent)
{
for (int i = 0; i < amount; ++i)
{
Vector3 position = RandomPosition();
GameObject instantiatedObject = objects[Random.Range(0, objects.Length)];
GameObject instantiated = Instantiate(instantiatedObject, position, Quaternion.identity) as GameObject;
instantiated.transform.parent = parent;
}
}
/// <summary>
/// Sets up the floors and the extraWalls
/// </summary>
/// <param name="extraWalls">for dev purposes, amount extra walls to be spreaaround the map</param>
public void SetUpScene(int extraWalls)
{
InitializeFloorPositionsList();
SetUpWalls();
LayoutObjectsAtRandom(wallTiles, extraWalls, wallsHolder);
LayoutObjectsAtRandom(floorTiles, floorPositions.Count, floorHolder);
}
}
}
As you can see, I followed the tutorial and eventually there's a Transform that holds all the instantiated map parts - it's called "Board" and it holds two other Transforms called "Floors" and "Walls", holding the floors and the walls.
How would you manage to solve those 3 problems I stated above?
I'm just a beginner at Unity, I'm just a C#/C++ developer so naturally XNA was simpler for me because it was a lot more code-centered than unity.
Edit: this is the CameraController script:
using UnityEngine;
namespace Assets.Scripts
{
public class CameraController : MonoBehaviour
{
public Transform player;
public Vector2 margin, smoothing;
public bool IsFollowing { get; set; }
public void Start()
{
IsFollowing = true;
}
public void Update()
{
var x = transform.position.x;
var y = transform.position.y;
if (IsFollowing)
{
if (Mathf.Abs(x - player.position.x) > margin.x)
x = Mathf.Lerp(x, player.position.x, smoothing.x * Time.deltaTime);
if (Mathf.Abs(y - player.position.y) > margin.y)
y = Mathf.Lerp(y, player.position.y, smoothing.y * Time.deltaTime);
}
transform.position = new Vector3(x, y, transform.position.z);
}
}
}

Related

SceneManager.LoadScene() is not working in the way i want

In my unity project i have 3 scenes.
Title
Play
Over
For achieving the flow Title -> Play -> Over. I had to start the game from Over scene. Over -> Title -> Play -> Over .. I don't want this. I want it to work when i start the game from Title scene. On doing so i am unable to change from Play -> Over.
for Title scene
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadSceneOnInput : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetAxis("Submit") == 1) {
SceneManager.LoadScene("Play");
}
}
}
for Over Scene
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameOverInput : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetAxis("Submit") == 1) {
SceneManager.LoadScene("Title");
}
}
}
Play's script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelGenerator : MonoBehaviour {
public GameObject floorPrefab;
public GameObject wallPrefab;
public GameObject ceilingPrefab;
public GameObject characterController;
public GameObject floorParent;
public GameObject wallsParent;
// allows us to see the maze generation from the scene view
public bool generateRoof = true;
// number of times we want to "dig" in our maze
public int tilesToRemove = 50;
public int mazeSize;
// spawns at the end of the maze generation
public GameObject pickup;
// this will determine whether we've placed the character controller
private bool characterPlaced = false;
// 2D array representing the map
private bool[,] mapData;
// we use these to dig through our maze and to spawn the pickup at the end
private int mazeX = 4, mazeY = 1;
// Use this for initialization
void Start () {
// initialize map 2D array
mapData = GenerateMazeData();
// create actual maze blocks from maze boolean data
for (int z = 0; z < mazeSize; z++) {
for (int x = 0; x < mazeSize; x++) {
if (mapData[z, x]) {
CreateChildPrefab(wallPrefab, wallsParent, x, 1, z);
CreateChildPrefab(wallPrefab, wallsParent, x, 2, z);
CreateChildPrefab(wallPrefab, wallsParent, x, 3, z);
} else if (!characterPlaced) {
// place the character controller on the first empty wall we generate
characterController.transform.SetPositionAndRotation(
new Vector3(x, 1, z), Quaternion.identity
);
// flag as placed so we never consider placing again
characterPlaced = true;
CreateChildPrefab(floorPrefab, floorParent, x, 0, z);
}
//create floor and ceiling
if(mapData[z, x]){
CreateChildPrefab(floorPrefab, floorParent, x, 0, z);
}else{
if((z > 0 && z < mazeSize - 1) && (x > 0 && x < mazeSize - 1)){
if(!(Random.value > 0.8)){
CreateChildPrefab(floorPrefab, floorParent, x, 0, z);
}
}
}
if (generateRoof) {
CreateChildPrefab(ceilingPrefab, wallsParent, x, 4, z);
}
}
}
// spawn the pickup at the end
var myPickup = Instantiate(pickup, new Vector3(mazeX, 1, mazeY), Quaternion.identity);
myPickup.transform.localScale = new Vector3(0.25f, 0.25f, 0.25f);
}
void Update() {
if(characterController.transform.position.y < -5){
SceneManager.LoadScene("Over");
}
}
// generates the booleans determining the maze, which will be used to construct the cubes
// actually making up the maze
bool[,] GenerateMazeData() {
bool[,] data = new bool[mazeSize, mazeSize];
// initialize all walls to true
for (int y = 0; y < mazeSize; y++) {
for (int x = 0; x < mazeSize; x++) {
data[y, x] = true;
}
}
// counter to ensure we consume a minimum number of tiles
int tilesConsumed = 0;
// iterate our random crawler, clearing out walls and straying from edges
while (tilesConsumed < tilesToRemove) {
// directions we will be moving along each axis; one must always be 0
// to avoid diagonal lines
int xDirection = 0, yDirection = 0;
if (Random.value < 0.5) {
xDirection = Random.value < 0.5 ? 1 : -1;
} else {
yDirection = Random.value < 0.5 ? 1 : -1;
}
// random number of spaces to move in this line
int numSpacesMove = (int)(Random.Range(1, mazeSize - 1));
// move the number of spaces we just calculated, clearing tiles along the way
for (int i = 0; i < numSpacesMove; i++) {
mazeX = Mathf.Clamp(mazeX + xDirection, 1, mazeSize - 2);
mazeY = Mathf.Clamp(mazeY + yDirection, 1, mazeSize - 2);
if (data[mazeY, mazeX]) {
data[mazeY, mazeX] = false;
tilesConsumed++;
}
}
}
return data;
}
// allow us to instantiate something and immediately make it the child of this game object's
// transform, so we can containerize everything. also allows us to avoid writing Quaternion.
// identity all over the place, since we never spawn anything with rotation
void CreateChildPrefab(GameObject prefab, GameObject parent, int x, int y, int z) {
var myPrefab = Instantiate(prefab, new Vector3(x, y, z), Quaternion.identity);
myPrefab.transform.parent = parent.transform;
}
}

Generating random Path in 2D Grid in C# (Tower Defense)

im trying to create a 2D TowerDefense Game and i´m stuck with creating a random Path between a random start- and endpoint. These two points are located at the top edge and bottom edge respectively.
Currently my code is looking for the direction on the x axis where the end point is. If the path is level with the end point, a straight path is generated to that point.
But I want more variety. The path shouldn't just go left or right and then down. For example, I want something like curves, but the path must not collide.
I hope someone can help me with my Code.
Code:
public class MapGenerator : MonoBehaviour
{
public GameObject mapTile;
[SerializeField] private int mapWidth; //set in the unity environment
[SerializeField] private int mapHeight; //set in the unity environment
public static List<GameObject> mapTiles = new List<GameObject>();
public static List<GameObject> pathTiles = new List<GameObject>();
public static GameObject startTile;
public static GameObject endTile;
private bool reachedX = false;
private bool reachedY = false;
private GameObject currentTile;
private int currentIndex;
private int nextIndex;
public Color startTileColor;
public Color endTileColor;
public Color mapColor;
public Color pathColor;
private void Start()
{
generateMap();
}
//selecting all Tiles at the top Edge
private List<GameObject> getTopEdgeTiles()
{
List<GameObject> edgeTiles = new List<GameObject>();
for (int i = mapWidth * (mapHeight - 1); i < mapWidth * mapHeight; i++)
{
edgeTiles.Add(mapTiles[i]);
}
return edgeTiles;
}
//selecting all Tiles at the bottom Edge
private List<GameObject> getBottomEdgeTiles()
{
List<GameObject> edgeTiles = new List<GameObject>();
for (int i = 0; i < mapWidth; i++)
{
edgeTiles.Add(mapTiles[i]);
}
return edgeTiles;
}
//void for moving down
private void moveDown()
{
pathTiles.Add(currentTile); //adding currentTile to PathTile
currentIndex = mapTiles.IndexOf(currentTile); //getting current Index of Tile in mapTiles
nextIndex = currentIndex - mapWidth; //setting next Index
currentTile = mapTiles[nextIndex]; //setting next currentTile
}
//void for moving left
private void moveLeft()
{
pathTiles.Add(currentTile);
currentIndex = mapTiles.IndexOf(currentTile);
nextIndex = currentIndex - 1;
currentTile = mapTiles[nextIndex];
}
//void for moving right
private void moveRight()
{
pathTiles.Add(currentTile);
currentIndex = mapTiles.IndexOf(currentTile);
nextIndex = currentIndex + 1;
currentTile = mapTiles[nextIndex];
}
private void generateMap()
{
//setup 2D Map
for (int y = 0; y < mapHeight; y++)
{
for (int x = 0; x < mapWidth; x++)
{
GameObject newTile = Instantiate(mapTile);
mapTiles.Add(newTile);
newTile.transform.position = new Vector2(x, y);
}
}
List<GameObject> topEdgeTiles = getTopEdgeTiles();
List<GameObject> bottomEdgeTiles = getBottomEdgeTiles();
int rand1 = Random.Range(0, mapWidth);
int rand2 = Random.Range(0, mapWidth);
startTile = topEdgeTiles[rand1]; //random starting point
endTile = bottomEdgeTiles[rand2]; //random end point
currentTile = startTile;
moveDown();
//starting the path algorithm
bool moving = true;
while (moving)
{
if (!reachedX)
{
if (currentTile.transform.position.x > endTile.transform.position.x)
{
moveLeft();
}
else if (currentTile.transform.position.x < endTile.transform.position.x)
{
moveRight();
}
else
{
reachedX = true;
}
}
else if(!reachedY) {
if (currentTile.transform.position.y > endTile.transform.position.y)
{
moveDown();
}
else
{
reachedY = true;
}
}
else if (reachedX && reachedY)
{
moving = false;
}
}
pathTiles.Add(endTile);
//setting colors for each tile
foreach (GameObject obj in mapTiles)
{
obj.GetComponent<SpriteRenderer>().color = mapColor;
}
foreach (GameObject obj in pathTiles)
{
obj.GetComponent<SpriteRenderer>().color = pathColor;
}
startTile.GetComponent<SpriteRenderer>().color = startTileColor;
endTile.GetComponent<SpriteRenderer>().color = endTileColor;
}
}
This generate something like:
current path generation
An I want something like that:
my imagination
Thank you and Best Regards!
I actually tried a bunch of different ways of producing random paths. They all worked, but in all cases the vast majority of the paths that were generated were not pleasing -- not enough wiggles or not using most of the available area.
This is a way that I think would work well, but it would be a fair bit of code:
Generate about 4 or 5 random points. Make sure you have at least one in each quadrant.
Calculate the Voronoi diagram of those points, along with the entrance and exit.
Try to find a Hamiltonian path through the diagram from the entrance to the exit. If you can't find one, then just take the longest simple path that you found.
In each Voronoi cell, connect the path entry point to the exit point with a smooth curve.
The Hamiltonian path, along with the requirement to have a point in each quadrant, ensures that the path uses the available space well. The number of random points determines how tight the curves are.

How can I randomize the public Transform tilePrefab in my code?

So I want to make a map generator and have a prefab for a tile. But I want to make more tiles which it randomly chooses from.
How can I make it that tilePrefab is chosen randomly every time from an array of prefabs?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MapGenerator : MonoBehaviour
{
public Transform tilePrefab; //This is the part which I want to be random
public Vector2 mapSize;
private void Start()
{
GenerateMap();
}
public void GenerateMap()
{
for (int x = 0; x < mapSize.x; x++)
{
for (int y = 0; y < mapSize.y; y++)
{
Vector3 tilePosition = new Vector3(-mapSize.x / 2 + 0.5f + x, 0,-mapSize.y / 2 + 0.5f + y);
Transform newTile = Instantiate(tilePrefab, tilePosition, Quaternion.Euler(Vector3.right * 360)) as Transform;
}
}
}
}
I want that tilePrefab is chosen randomly every time a tile gets generated.
Have an array that holds all the tile prefabs. Randomly choose an index for your new tile.
Transform newTile = Instantiate(tilePrefabs[Random.Range(0, tilePrefabs.Length - 1), tilePosition, Quaternion.Euler(Vector3.right * 360)) as Transform;

Setting the spawn position for a 3D object

I am making an endless runner style game in unity where the floor tiles spawn randomly and endlessly in front of the player as they run and delete themselves after a certain distance behind the player this is all working fine and as intended however the individual tiles spawn about half way inside each other and as much as I try to debug my code I can't seem to effect them. Ideally, I want the code to do exactly what it's doing, but the tiles spawn end to end rather than inside each other.
Any help would be greatly appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tile_Manager : MonoBehaviour
{
public GameObject[] tilePrefabs;
private Transform playerTransform;
private float spawnZ = 5.0f;
private float tileLength = 5.0f;
private float safeZone = 7.0f;
private int amtTilesOnScreen = 10;
private int lastPrefabIndex = 0;
private List<GameObject> activeTiles;
// Use this for initialization
void Start () {
activeTiles = new List<GameObject>();
playerTransform = GameObject.FindGameObjectWithTag ("Player").transform;
for (int i = 0; i < amtTilesOnScreen; i++)
{
if (i < 2)
SpawnTile(0);
else
SpawnTile();
}
}
// Update is called once per frame
void Update () {
if (playerTransform.position.z - safeZone > (spawnZ - amtTilesOnScreen * tileLength))
{
SpawnTile();
DeleteTile();
}
}
private void SpawnTile(int prefabIndex = -1)
{
GameObject go;
if (prefabIndex == -1)
go = Instantiate(tilePrefabs[RandomPrefabIndex()]) as GameObject;
else
go = Instantiate(tilePrefabs[prefabIndex]) as GameObject;
go.transform.SetParent(transform);
go.transform.position = Vector3.forward * spawnZ;
spawnZ += tileLength;
activeTiles.Add (go);
}
private void DeleteTile()
{
Destroy(activeTiles [0]);
activeTiles.RemoveAt (0);
}
private int RandomPrefabIndex()
{
if (tilePrefabs.Length <= 1)
return 0;
int randomIndex = lastPrefabIndex;
while (randomIndex == lastPrefabIndex)
{
randomIndex = Random.Range(0, tilePrefabs.Length);
}
lastPrefabIndex = randomIndex;
return randomIndex;
}
}
stacked tiles
You need to take the length of a tile into account. Try changing this
go.transform.position = Vector3.forward * spawnZ;
to this
go.transform.position = Vector3.forward * (spawnZ + tileLength / 2);
to add half the tile length to the spawn position.
Wouldn't you want
go.transform.Translate(Vector3.forward * spawnZ);
not position?
As you're spawning things relative to the world coordinate system.
https://docs.unity3d.com/ScriptReference/Transform.Translate.html

objects using their own unique waypoints array

update...
First Class
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Wave
{
public GameObject enemyPrefab;
public float spawnInterval = 2;
public int maxEnemies = 20;
}
public class SpawnEnemy : MonoBehaviour
{
public GameObject[] waypoints;
public GameObject testEnemyPrefab;
public Wave[] waves;
public int timeBetweenWaves = 5;
private GameManagerBehavior gameManager;
private float lastSpawnTime;
private int enemiesSpawned = 0;
// Use this for initialization
void Start()
{
lastSpawnTime = Time.time;
gameManager =
GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
}
// Update is called once per frame
void Update()
{
// 1 Get the index of the current wave, and check if it’s the last one.
int currentWave = gameManager.Wave;
if (currentWave < waves.Length)
{
// 2 If so, calculate how much time passed since the last enemy spawn and whether it’s time to spawn an enemy. Here you consider two cases.
// If it’s the first enemy in the wave, you check whether timeInterval is bigger than timeBetweenWaves.
// Otherwise, you check whether timeInterval is bigger than this wave’s spawnInterval. In either case, you make sure you haven’t spawned all the enemies for this wave.
float timeInterval = Time.time - lastSpawnTime;
float spawnInterval = waves[currentWave].spawnInterval;
if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
timeInterval > spawnInterval) &&
enemiesSpawned < waves[currentWave].maxEnemies)
{
// 3 If necessary, spawn an enemy by instantiating a copy of enemyPrefab. You also increase the enemiesSpawned count.
lastSpawnTime = Time.time;
GameObject newEnemy = (GameObject)
Instantiate(waves[currentWave].enemyPrefab);
newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
newEnemy.GetComponent<MoveEnemy>().JiggleWaypoints();
enemiesSpawned++;
}
// 4 You check the number of enemies on screen. If there are none and it was the last enemy in the wave you spawn the next wave.
// You also give the player 10 percent of all gold left at the end of the wave.
if (enemiesSpawned == waves[currentWave].maxEnemies &&
GameObject.FindGameObjectWithTag("Enemy") == null)
{
gameManager.Wave++;
gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f);
enemiesSpawned = 0;
lastSpawnTime = Time.time;
}
// 5 Upon beating the last wave this runs the game won animation.
}
else {
gameManager.gameOver = true;
GameObject gameOverText = GameObject.FindGameObjectWithTag("GameWon");
gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
}
}
}
Second Class
using UnityEngine;
using System.Collections;
public class MoveEnemy : MonoBehaviour
{
[System.NonSerialized]
public GameObject[] waypoints;
private int currentWaypoint = 0;
private float lastWaypointSwitchTime;
public float speed = 1.0f;
// Use this for initialization
void Start()
{
lastWaypointSwitchTime = Time.time;
}
// Update is called once per frame
void Update()
{
// 1
Vector3 startPosition = waypoints[currentWaypoint].transform.position;
Vector3 endPosition = waypoints[currentWaypoint + 1].transform.position;
// 2
float pathLength = Vector3.Distance(startPosition, endPosition);
float totalTimeForPath = pathLength / speed;
float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
gameObject.transform.position = Vector3.Lerp(startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
// 3
if (gameObject.transform.position.Equals(endPosition))
{
if (currentWaypoint < waypoints.Length - 2)
{
// 3.a
currentWaypoint++;
lastWaypointSwitchTime = Time.time;
RotateIntoMoveDirection();
}
else {
// 3.b
Destroy(gameObject);
AudioSource audioSource = gameObject.GetComponent<AudioSource>();
AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
//<< deduct health
GameManagerBehavior gameManager =
GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
gameManager.Health -= 1;
//>>
}
}
}
public void JiggleWaypoints()
{
for (int i = 1; i < waypoints.Length; i++)
{
waypoints[i].transform.position = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 3), waypoints[i].transform.position.y + Random.Range(-3, 3), 0);
}
}
private void RotateIntoMoveDirection()
{
//1 It calculates the bug’s current movement direction by subtracting the current waypoint’s position from that of the next waypoint.
Vector3 newStartPosition = waypoints[currentWaypoint].transform.position;
Vector3 newEndPosition = waypoints[currentWaypoint + 1].transform.position;
Vector3 newDirection = (newEndPosition - newStartPosition);
//2 It uses Mathf.Atan2 to determine the angle toward which newDirection points, in radians, assuming zero points to the right.
// Multiplying the result by 180 / Mathf.PI converts the angle to degrees.
float x = newDirection.x;
float y = newDirection.y;
float rotationAngle = Mathf.Atan2(y, x) * 180 / Mathf.PI;
//3 Finally, it retrieves the child named Sprite and rotates it rotationAngle degrees along the z-axis.
// Note that you rotate the child instead of the parent so the health bar — you’ll add it soon — remains horizontal.
GameObject sprite = (GameObject)
gameObject.transform.FindChild("Sprite").gameObject;
sprite.transform.rotation =
Quaternion.AngleAxis(rotationAngle, Vector3.forward);
}
public float distanceToGoal()
{
float distance = 0;
distance += Vector3.Distance(
gameObject.transform.position,
waypoints[currentWaypoint + 1].transform.position);
for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++)
{
Vector3 startPosition = waypoints[i].transform.position;
Vector3 endPosition = waypoints[i + 1].transform.position;
distance += Vector3.Distance(startPosition, endPosition);
}
return distance;
}
}
Code is working 100% without errors, BUT....
After each spawn all objects get the same waypoint array. This can be seen on the screen as all objects jump to new waypoint in line together each time new object is spawned. I want the object which is already spawn to live life with it's own array of only once created waypoints.
You need to create a new array of waypoints each time you create one from the prefabricated object. You don't show your Instantiate method but I'm guessing that it has a line like this:
this.waypoints = prefab.waypoints;
This will mean that all object you create will share the same list of waypoints (as you've discovered).
What you need is something like this - assuming that the waypoints have X, Y, and Z properties):
this.waypoints = new GameObject[5];
for (int i = 0; i++ ; i < 5)
{
this.waypoints[i].X = prefab.waypoints[i].X;
this.waypoints[i].Y = prefab.waypoints[i].Y;
this.waypoints[i].Z = prefab.waypoints[i].Z;
}
(If you want your points to be a variable length you might want to consider using a list).
This means that each object has a list of unique points even if they start with the same values you can change each independently.
Based on ChrisFs' and Joe Blows' answers, do something like this in your MoveEnemy script:
private Vector3[] myWay;
public void JiggleWaypoints(GameObject[] waypoints)
{
myWay = new Vector3[waypoints.Length];
for(int i = 1; i < waypoints.Length; i++)
{
myWay[i] = new Vector3(waypoints[i].transform.position.x + Random.Range(-3, 4), waypoints[i].transform.position.y + Random.Range(-3, 4), 0);
}
}
myWay replaces the GameObject[].
In your SpawnEnemy script you do this:
GameObject e = (GameObject)Instantiate(enemyPrefab);
e.GetComponent<MoveEnemy>().JiggleWaypoints(waypoints);

Categories