- Home /
[SOLVED] Problem with random generated path for 2D game
Hello, I am making simple 2D game, something like endless runner(using C#). To make it I am using cube(tile) for random generated path(infinity). Tile have 3 attach(left,right,top) point, so they will spawn to correct place, those attach point is empty game object that is childed to Tile. Using 3 differend prefabs: TopTile, LeftTile, RightTile all of them have same attach points.
Tile Manager script
public class TileManager : MonoBehaviour {
public GameObject currentTile;
public GameObject[] tilePrefabs;
private static TileManager instance;
private Stack<GameObject> leftTiles = new Stack<GameObject>();
public Stack<GameObject> LeftTiles
{
get { return leftTiles; }
set { leftTiles = value; }
}
private Stack<GameObject> topTiles = new Stack<GameObject>();
public Stack<GameObject> TopTiles
{
get { return topTiles; }
set { topTiles = value; }
}
private Stack<GameObject> rightTiles = new Stack<GameObject>();
public Stack<GameObject> RightTiles
{
get { return rightTiles; }
set { rightTiles = value; }
}
public static TileManager Instance
{
get
{
if (instance == null)
{
instance = GameObject.FindObjectOfType<TileManager>();
}
return instance;
}
}
// Use this for initialization
void Start () {
CreateTiles(150);
GameEventManager.GameStart += GameStart;
GameEventManager.GameOver += GameOver;
for (int i = 0; i < 75; i++)
{
SpawnTile();
}
}
public void CreateTiles(int amount)
{
//creating new tiles for random generated path (using stacks)
for (int i = 0; i < amount; i++)
{
leftTiles.Push(Instantiate(tilePrefabs[0]));
topTiles.Push(Instantiate(tilePrefabs[1]));
rightTiles.Push(Instantiate(tilePrefabs[2]));
leftTiles.Peek().SetActive(false);
topTiles.Peek().SetActive(false);
rightTiles.Peek().SetActive(false);
leftTiles.Peek().name = "LeftTile";
topTiles.Peek().name = "TopTile";
rightTiles.Peek().name = "RightTile";
}
}
/// <summary>
/// need make condition that tile from current position can spawn only in 2 direction
/// example, if currect position is LeftTile, then next tile will be left or top
/// if right, then right or top
/// if top, only then next tile can be right, left or top
/// </summary>
public void SpawnTile()
{
//generate random number 0-2
int randomIndex = Random.Range(0, 3);
//condition for checking if there is tiles for path
if (leftTiles.Count == 0 || topTiles.Count == 0 || rightTiles.Count == 0)
{
CreateTiles(100);
}
//swamping tiles
if (randomIndex == 0)
{
GameObject temp = leftTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
else if (randomIndex == 1)
{
GameObject temp = topTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
else if(randomIndex == 2)
{
GameObject temp = rightTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
else
{
Debug.LogError("Don't have that tile");
}
}
}
Tile script
public class Tile : MonoBehaviour {
private float fallDelay = 1.5f;
void OnTriggerEnter(Collider collider)
{
//condition for tile falldown and spawning next amount of tiles(path) when player enter tile
if (collider.tag == "Player")
{
Debug.Log("Spawn next tile");
TileManager.Instance.SpawnTile();
StartCoroutine(FallDown());
}
}
IEnumerator FallDown()
{
//wait few seconds for doing operation in line below
yield return new WaitForSeconds(fallDelay);
GetComponent<Rigidbody>().isKinematic = false;
yield return new WaitForSeconds(fallDelay + 0.5f);
//"case of" condition for deciding which tiles push in correct stack, disable it and set rigidbody isKinematic to true
switch (gameObject.name)
{
case "LeftTile":
TileManager.Instance.LeftTiles.Push(gameObject);
gameObject.GetComponent<Rigidbody>().isKinematic = true;
gameObject.SetActive(false);
break;
case "TopTile":
TileManager.Instance.TopTiles.Push(gameObject);
gameObject.GetComponent<Rigidbody>().isKinematic = true;
gameObject.SetActive(false);
break;
case "RightTile":
TileManager.Instance.RightTiles.Push(gameObject);
gameObject.GetComponent<Rigidbody>().isKinematic = true;
gameObject.SetActive(false);
break;
default:
break;
}
}
}
With this code i get randomly spawned tiles, but not something I needed. What i get with this code.
What i wanted to get, but not sure how to implement it.
So far I noticed that i need some condition in function SpawnTIles, but can't figure out how to make it. I want that if there is spawning tiles to left side(for example), then right tiles wont be spawning or something like that. Hope you will help me.
P.S. Sorry for not smart comments in code, I made them to not forget what that code lines do(for myself).
Problem is in SpawnTile
else if(randomIndex == 2)
{
GameObject temp = rightTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
Those line, without them it's working almost how i wanted, but without right turn in road.
I modified my SpawnTile method to something like that.
public void SpawnTile()
{
int randomIndex = Random.Range(0, 3);
int spawnIndex = Random.Range(0, 2);
//condition for checking if there is tiles for path if not then creating new tiless
if (leftTiles.Count == 0 || topTiles.Count == 0 || rightTiles.Count == 0)
{
CreateTiles(100);
}
//spawning tiles
if (spawnIndex == 0)//spawn tiles to left
{
if (randomIndex == 0)
{
GameObject temp = leftTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
else if (randomIndex == 1)
{
GameObject temp = topTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
}
else if (spawnIndex == 1) //spawn tiles to right
{
if (randomIndex == 1)
{
GameObject temp = topTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
else if (randomIndex == 2)
{
GameObject temp = rightTiles.Pop();
temp.SetActive(true);
temp.transform.position = currentTile.transform.GetChild(0).transform.GetChild(randomIndex).position;
currentTile = temp;
}
}
else
{
Debug.LogError("Don't have that tile");
}
If comment one of those if statment example(if (spawnIndex == 0)//spawn tiles to left), random path will generate only to left side, same with other spawnIndex if condition, but tiles will spawn to right side. Trying to figure out how to combine them so both will work fine at same time.
Answer by Apeinans · May 13, 2016 at 12:35 PM
Add three new variables
private GameObject next;
private GameObject nextRight;
private GameObject tile;
And modified my SpawnTiles method to:
public void SpawnTile()
{
int randomIndex = Random.Range(0, 2);
int rr = Random.Range(0, 2);
int rrt = Random.Range(0, 2);
//condition for checking if there is tiles for path if not then creating new tiless
if (leftTiles.Count == 0 || lTopTiles.Count == 0 || rightTiles.Count == 0 || rTopTiles.Count == 0)
{
CreateTiles(100);
}
//spawning bonuses
Bonuses();
//spawning tiles
if (tile == currentTile)
{
Debug.Log("Left tile");
//spawn tiles to left or top
if (randomIndex == 0)
{
currentTile = Instantiate(tilePrefabs[0], currentTile.transform.GetChild(0).transform.GetChild(0).position, Quaternion.identity) as GameObject;
tile = currentTile;
}
else if (randomIndex == 1)
{
currentTile = Instantiate(tilePrefabs[1], currentTile.transform.GetChild(0).transform.GetChild(1).position, Quaternion.identity) as GameObject;
next = currentTile;
}
}
else if(next == currentTile)
{
Debug.Log("Top tile");
//spawn tiles to top with condition parameter which decide to turn right/left
if (rrt == 0)
{
currentTile = Instantiate(tilePrefabs[1], currentTile.transform.GetChild(0).transform.GetChild(1).position, Quaternion.identity) as GameObject;
tile = currentTile;
}
else if (rrt == 1)
{
currentTile = Instantiate(tilePrefabs[1], currentTile.transform.GetChild(0).transform.GetChild(1).position, Quaternion.identity) as GameObject;
nextRight = currentTile;
}
}
else if(nextRight == currentTile)
{
Debug.Log("Right tile");
//spawn tiles to right or top
if (rr == 0)
{
currentTile = Instantiate(tilePrefabs[2], currentTile.transform.GetChild(0).transform.GetChild(0).position, Quaternion.identity) as GameObject;
currentTile = Instantiate(tilePrefabs[2], currentTile.transform.GetChild(0).transform.GetChild(0).position, Quaternion.identity) as GameObject;
nextRight = currentTile;
}
else if (rr == 1)
{
currentTile = Instantiate(tilePrefabs[1], currentTile.transform.GetChild(0).transform.GetChild(1).position, Quaternion.identity) as GameObject;
currentTile = Instantiate(tilePrefabs[1], currentTile.transform.GetChild(0).transform.GetChild(1).position, Quaternion.identity) as GameObject;
tile = currentTile;
}
}
}
I know that it's best solution but still it work how i wanted.