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

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.

Related

My position generation method doesn't work

I have a method that is supposed to generate a certain number of Vector3 at a distance not less than specified.
// Generate random point based on plane area
public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
{
float entireArea = 0f;
List<AreasWeight> areasWeights = new List<AreasWeight>();
List<Vector3> positions = new List<Vector3>();
foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
{
entireArea += plane.GetArea();
}
foreach (GeneratorPlane plane in GeneratorPlanes.GetCollectionAsList())
{
float weight = plane.GetArea() / entireArea;
int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
areasWeights.Add(new(plane, weight, numOfPositionsInArea));
}
foreach (AreasWeight areaWeight in areasWeights)
{
for (int i = 0; i < areaWeight.NumOfPointsInArea; i++)
{
Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
foreach (Vector3 position in positions)
{
int attempts = 1;
while ((position - generatedPoint).magnitude < minDistanceBetweenPositions)
{
generatedPoint = areaWeight.Plane.GetRandomPointOnPlane();
attempts++;
if (attempts > 2000)
{
Debug.Log("Can't generate all positions.");
break;
}
}
}
positions.Add(generatedPoint);
}
}
return positions;
}
Get random point method:
public Vector3 GetRandomPointOnPlane()
{
float xPosition = Random.Range(Mathf.Min(DownPoint.x, DownPointHelper.x), Mathf.Max(DownPoint.x, DownPointHelper.x));
float zPosition = Random.Range(Mathf.Min(DownPoint.z, UpPointHelper.z), Mathf.Max(DownPoint.z, UpPointHelper.z));
return new(xPosition, DownPoint.y + 0.002f, zPosition);
}
But when i Instantiate objects based on these Vector3. Objects still have a distance less than the specified. What am i doing wrong?
I found a solution. The problem was a bad loop structure. When the algorithm confirmed that the distance was too small and generated a new one, it did not check whether the generated position had a gap from the previous positions on the list. It only confirmed that the gap was preserved and the program continued to execute.
I moved the code that makes sure that the distances are saved to the public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions) method in the GeneratorPlane class. I also added a private Vector3 PickRandomPos() method to it, just to return the generated position.
Methods in the public class GeneratorPlane:
public Vector3 GetRandomPointOnPlane(List<Vector3> alreadyGeneratedPoints, float minDistnaceBetweenPositions)
{
if (alreadyGeneratedPoints.Count != 0)
{
int attemps = 1;
bool pointFound = false;
Vector3 posToReturn = new();
while (!pointFound)
{
pointFound = true;
posToReturn = PickRandomPos();
foreach (Vector3 position in alreadyGeneratedPoints)
{
if (Vector3.Distance(position, posToReturn) < minDistnaceBetweenPositions)
{
pointFound = false;
attemps++;
if (attemps > 2000)
{
Debug.LogError("Points cannot be generated. Too little available space");
return Vector3.zero;
}
break;
}
}
}
return posToReturn;
}
else
{
Debug.Log("First point generated");
return PickRandomPos();
}
}
private Vector3 PickRandomPos()
{
float xPosition = Random.Range(Mathf.Min(DownPoint.x, DownPointHelper.x), Mathf.Max(DownPoint.x, DownPointHelper.x));
float zPosition = Random.Range(Mathf.Min(DownPoint.z, UpPointHelper.z), Mathf.Max(DownPoint.z, UpPointHelper.z));
return new(xPosition, DownPoint.y + 0.002f, zPosition);
}
Method to generate and return a certain number of items:
public List<Vector3> GeneratePositions(int numberOfPositions, float minDistanceBetweenPositions)
{
float entireArea = 0f;
List<AreasWeight> areasWeights = new();
List<Vector3> positions = new();
foreach (GeneratorPlane plane in PlanesGenerator.GetCollectionAsList())
{
entireArea += plane.GetArea();
}
foreach (GeneratorPlane plane in PlanesGenerator.GetCollectionAsList())
{
float weight = plane.GetArea() / entireArea;
int numOfPositionsInArea = Mathf.RoundToInt(numberOfPositions * weight);
areasWeights.Add(new(plane, weight, numOfPositionsInArea));
}
foreach (AreasWeight areaWeight in areasWeights)
{
for (int i = 0; i < areaWeight.NumOfPointsInArea; i++)
{
Vector3 generatedPoint = areaWeight.Plane.GetRandomPointOnPlane(positions, minDistanceBetweenPositions);
positions.Add(generatedPoint);
}
}
return positions;
}
On the original code if you generate a point 2000 times you actually keep the last generatedPoint, and as you mentioned you don't actually cross check the whole list of positions, only the remaining positions.
Although you have solved your problem and posted a solution, I took the liberty of doing a simple script with the same end, I will share it here in hopes its useful for you or others.
This solution will not fill any area, its only making sure no two objects are at shorter distance than specified.
In my tests, with 50 nPoints only 10/20 points are instantiated before a point takes over 2000 attempts and consequently conclude the search for points. Although this will depend on the ratio between spawnLimits and nPoints.
[SerializeField]
GameObject trunkPrefab;
List<Vector3> positions;
//input variables
int nPoints = 50;
float minDistance = 2.5f;
int spawnLimits = 20;
void Start()
{
positions = new();
for (int i = 0; i < nPoints; i++)
{
Vector3 position = Vector3.zero;
bool newPosition = true;
int attempts = 0;
do
{
//first generation will be automatically added to the list
position = new(Random.Range(-spawnLimits, spawnLimits), .5f, Random.Range(-spawnLimits, spawnLimits));
if (positions.Count < 1)
{
break;
}
//every position will be compared here,
//if any position is too close from then new position
//"newPosition" is set to false and we try again from the start.
for (int p = 0; p < positions.Count; p++)
{
if (Vector3.Distance(position, positions[p]) < minDistance)
{
newPosition = false;
attempts++;
if (attempts > 2000)
{
Debug.Log("Max attempts reached.");
return;
}
break;
}
}
} while (!newPosition);
//adding a random rotation
Vector3 rotation = new(Random.Range(80, 100), Random.Range(0, 179), 0);
Instantiate(trunkPrefab, position, Quaternion.Euler(rotation));
positions.Add(position);
}
}

What is the fastest method to create and render large number of 2d sprites in Unity?

I am creating an infinite terrain generator and I need to constantly update the terrain as the player moves around.
Everything is fine, but I am having trouble with finding information about the fastest method of creating and rendering sprites on the fly.
Information about sprites:
I am using 1 sprite sheet which has all the frames I need for my terrain. Grass, sand, water etc. all in 1 single .png file. All frames are stored in an array from which I can easily grab them.
Steps I need to do to display my sprite object correctly currently:
Create new object.
Set their position in 2d space.
Add component.
Scale them as needed.
Generated sprites get stored in a GameObject array called chunk. This is the way I am currently generating sprites.
chunk[i] = new GameObject();
chunk[i].gameObject.transform.position = new Vector2(spriteCoordX, spriteCoordY);
chunk[i].AddComponent<SpriteRenderer>();
SpriteRenderer renderer = chunk[i].GetComponent<SpriteRenderer>();
renderer.sprite = tiles[calculatedFrameId]; //Set correct sprite frame.
chunk[i].gameObject.transform.localScale = new Vector2(6.75f , 6.75f);
I don't know, adding component and scaling every single time I want to create a new sprite in code seems redundant and unnecessary and I am sure there is a better way to do that.
To sum up:
I need the best (fastest) possible way to generate large number of sprites, set their frame, position and proper scale.
Cannot help posting this image here, as this is really of thousands of words, thanks #AidenH for the "Object pooling" comment!
I apologize this took me some time to get to... I ended up creating a project where I generate an open world, and I use Perlin Noise to generate portions of the map depending on where the player is(Since I dont have an actual terrain)
I used Object Pooling for this, so I have a World Manager that knows what the world looks like (or in my case it uses Perlin Noise), this WorldManager pools tiles.
NOTE: This is one way to do it, using Object Pooling.
So basically it would look something like this:
public class WorldManager : MonoBehaviour {
// Being cheap here for the time, if you use this route make sure to use a proper singleton pattern
static public WorldManager instance;
[SerializeField] // Created a prefab for all my tile objects
private TileObject tilePrefab;
[SerializeField]
private int StartingTilePool = 300;
[SerializeField] // In my case this list stored 1 sprite, and I just changed that sprite color depending on the value of perlin noise
List<Sprite> terrainSprites;
private Queue<TileObject> objectPool = new Queue<TileObject>();
void Start() {
instance = this; // Again use a proper singleton pattern in your project.
GenerateTilePool();
LoadFirstSetOfTiles();
}
private void LoadFirstSetOfTiles()
{
// my player always starts at 0,0..
for(int x = -SpawnTileBoundry.HorizontalExtents; x <= SpawnTileBoundry.HorizontalExtents; ++x)
{
for(int y = -SpawnTileBoundry.VerticalExtents; y <= SpawnTileBoundry.VerticalExtents; ++y)
{
SetActiveTile(x,y);
}
}
}
private void GenerateTilePool()
{
for(int i =0; i < tilesToGenerate; ++i)
{
TileObject tempTile = Instantiate(tilePrefab);
EnqueTile(tempTile);
}
}
public void EnqueTile(TileObject tile)
{
objectPool.Enqueue(tile);
tile.gameObject.SetActive(false);
}
public void SetActiveTile(int x, int y)
{
TileObject newTile = null;
if(objectPool.count > 0)
{
newTile = objectPool.Dequeue();
}
else
{
// We didn't have enough tiles store in our pool so lets make a new 1.
newTile = Instantiate(tilePrefab);
}
newTile.transform.position = new Vector3(x,y,1); // Used 1 to put it behind my player...
newTile.gameObject.SetActive(true);
// The sprite here would be based off of your world data, where mine is only a white box, I use the second parameters to give it a gray-scaled color.
newTile.UpdateSprite(terrainSprites[0], Mathf.PerlinNoise(x/10.0f, y / 10.0f));
}
}
That is just my WorldManager that handles ObjectPooling for me...
Here is my TileObject
[RequireComponent(typeof(SpriteRenderer))]
public class TileObject : MonoBehaviour {
private SpriteRenderer myRenderer;
private void Awake() {
myRenderer = getComponent<SpriteRenderer>();
}
void Update()
{
if(Mathf.Abs(transform.position.x - Camera.main.transform.position.x) > SpawnTileBoundry.HorizontalExtents || Mathf.Abs(transform.position.y - Camera.main.transform.position.y) > SpawnTileBoundry.VerticalExtents)
{
// With this check the tile knows it is no longer visible,
// I could have used OnBecameInvisible to handle this
// but I added a threshold to the extents, that prevent it so
// players would see tiles "appearing" this caused a nice bug, where
// if you moved just right a row/col of tiles wouldn't spawn.
WorldManager.instance.EnqueTile(this);
}
}
public void UpdateSprite(Sprite sprite)
{
myRenderer.sprite = sprite;
}
public void UpdateSprite(Sprite sprite, float grayColor)
{
UpdateSprite(sprite);
myRenderer.color = new Color(grayColor,grayColor,grayColor,1f);
}
}
Here is my SpawnTileBoundry script:
public class WorldManager : MonoBehaviour {
private int lastX = 0;
private int lastY = 0;
static public int HorizontalExtents;
static public int VerticalExtents;
void Start() {
VerticalExtents = (int)Camera.main.orthograpicSize + 2; // +2 is just my threshold
HorizontalExtents = (int)(VerticalExtents * Screen.width/Screen.height) +3; // +3 is just my threshold you can change these to what you want.
lastX = (int)transform.position.x;
lastY = (int)transform.position.y;
}
void Update() {
int newX = (int)transform.position.x;
int newY = (int)transform.position.y;
HandleNewTileSpawn(lastX - newX, lastY - newY);
}
// This will tell the WorldManager which tiles need to appear
// We are no longer creating new tiles unless we absolutely have to.
// We are also only making new tiles appear in the circumstance that
// we are about to see them.
void HandleNewTileSpawn(int x, int y)
{
if(x != 0)
{
// This code could be refactor to a method so it was less error prone for changes or tweaks...
if(x < 0)
{
for(int i = lastY - VerticalExtents; i < lastY + VerticalExtents; ++i)
{
WorldManager.instance.SetActiveTile(lastX + HorizontalExtents, i);
}
}
else
{
for(int i = lastY - VerticalExtents; i < lastY + VerticalExtents; ++i)
{
WorldManager.instance.SetActiveTile(lastX - HorizontalExtents, i);
}
}
lastX = (int)transform.position.x;
}
if(y != 0)
{
if(lastY < 0)
{
for(int i = lastX - HorizontalExtents; i < lastX + HorizontalExtents; ++i)
{
WorldManager.instance.SetActiveTile(i, lastY + VeritcalExtents);
}
}
else
{
for(int i = lastX - HorizontalExtents; i < lastX + HorizontalExtents; ++i)
{
WorldManager.instance.SetActiveTile(i, lastY - VeritcalExtents);
}
}
lastY = (int)transform.position.y;
}
}
}
I am using the WorldManager to handle my object pooling, yes I am still instantiating quite a few sprites at the beginning but then I eventually stop spawning as there is no need to keep spawning new objects.
Unity doesn't have alot in their documentation in regards to object pooling however they do have a video tutorial that goes over some of the basics of Object Pooling: https://unity3d.com/learn/tutorials/topics/scripting/object-pooling

Unity what's wrong with my instantiating algorithm?

I dont know if I can call this algorithm. But I am working on a game in which player will move in a circular path.
As you can see in the picture player is suppose to orbit the circle. And obstacle shall be instantiated in the circle.I am trying to first create the obstacle in first half(left to the long cube) and then in the second half. But things are getting created in the next half too when code is not supposed to do that. Also, it is showing argument exception error. Please have a look at my code and tell me whether my method is wrong or my formulas are wrong or anything else.
public class ObjectInstantiater : MonoBehaviour {
DataHolder dataholder;
GameObject Obstacle;
LevelData leveldata;
private int currentlevel=0; // default level starts from 0
private List<GameObject> Inactivegameobject = new List<GameObject>(); // this object can be used
private List<GameObject> Activegameobject = new List<GameObject>();
private int totalgameobjects;
private int firsthalfgameobjects, secondhalfgameobjects;
public float outerradius;
public float innerradius;
private bool shallspawnouterradiues = true;
// Use this for initialization
void Awake () {
dataholder = (Object)GameObject.FindObjectOfType<DataHolder>() as DataHolder;
Obstacle = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
leveldata = dataholder.Leveldata[0];
}
void Start()
{
Updateleveldata();
FirstHalf();
}
public int Currentlevel
{
get { return currentlevel; }
set { currentlevel = value;
leveldata = dataholder.Leveldata[currentlevel];//sets the level data
}
}
private void Updateleveldata() // this function gets called after a round
{
totalgameobjects = Random.Range(leveldata.MinimumObstacle, leveldata.MaximumObstacle);
firsthalfgameobjects = Mathf.RoundToInt(totalgameobjects / 2);
secondhalfgameobjects = totalgameobjects - firsthalfgameobjects;
}
private void FirstHalf()
{
Debug.Log(firsthalfgameobjects);
Vector3 pos;
if (Inactivegameobject.Count < firsthalfgameobjects)
{
for (int x = 0; x <= (firsthalfgameobjects - Inactivegameobject.Count); x++)
{
GameObject obs = Instantiate(Obstacle) as GameObject;
obs.SetActive(false);
Inactivegameobject.Add(obs);
}
}
float spawnangledivision = 180 / firsthalfgameobjects;
float spawnangle = 180f;
for(int x = 0; x < firsthalfgameobjects; x++)
{
float proceduralRandomangle = spawnangle;
proceduralRandomangle = Random.Range(proceduralRandomangle , proceduralRandomangle + 2f);
if (shallspawnouterradiues)
{
pos = new Vector3(outerradius * Mathf.Cos(spawnangle), outerradius * Mathf.Sin(spawnangle), 0f);
shallspawnouterradiues = false;
}else
{
pos = new Vector3(innerradius * Mathf.Cos(spawnangle), innerradius * Mathf.Sin(spawnangle), 0f);
shallspawnouterradiues = true;
}
spawnangle += spawnangledivision;
Inactivegameobject[0].SetActive(true); // set it to 0
Inactivegameobject[0].transform.position = pos;
Activegameobject.Add(Inactivegameobject[0]);
Inactivegameobject.RemoveAt(0);
}
}
private void SecondHalf()// No need to check this
{
if (Inactivegameobject.Count < firsthalfgameobjects)
{
GameObject obs = Instantiate(Obstacle) as GameObject;
obs.SetActive(false);
Inactivegameobject.Add(obs);
}
}
}

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

How can I reset a Vector3 position?

I'm attempting to write a script that instantiates a row of prefabs. This worked the first time, but every time after that it instantiates one at 0x,0y,0z and the rest ~30x-40x away. I tried setting the initial position before the for loop executes and then resetting the position using the initalPos variable, but that doesn't seem to work. in my code
public class generator : MonoBehaviour {
public int height = 0;
public int width = 0;
private Vector3 temp;
public GameObject sprite;
private Vector3 initialPos;
void Start ()
{
initialPos = new Vector3(0,0,0);
for(int i = 0; i < width; i++)
{
Instantiate (sprite, temp, Quaternion.identity);
temp = sprite.transform.position;
temp.x += 0.089f;
sprite.transform.position = temp;
}
temp = initialPos;
}
}
The temp variable is what I'm setting the current position to so I can add 0.089 to it so that my sprites will line up. I'm trying to reset that value so that they line up starting at 0x every time.
You can simplify your code by specifying the number of prefabs you wish to spawn in a row, rather than the exact width.
Additionally, instead of incrementing your spawn position x value by a hard coded number, use gameObject.transform.localScale.x instead.
For example:
public GameObject Cube;
void Start()
{
SpawnRow(Vector3.zero, 10);
}
void SpawnRow(Vector3 startPosition, int RowLength)
{
Vector3 currentPos = startPosition;
for (int i = 0; i < RowLength; i++)
{
Instantiate(Cube, currentPos, Quaternion.identity);
currentPos.x += Cube.transform.localScale.x;
}
}
Additionally, if you wanted to do something like spawn additional rows next to your each other, you could call SpawnRow() like this:
void Start()
{
Vector3 currentPos = Vector3.zero;
for (int i = 0; i < 3; i++)
{
SpawnRow(currentPos, 10);
currentPos.z += Cube.transform.localScale.z;
}
}
This would give you three rows of 10 gameObjects directly next to each other.

Categories