I’m trying to devise a random but selective spawning system. I want to spawn objects in the level using a random int, but stop spawning a specific one after it has already been spawned a number of times. If it has already spawned, another object should be spawned instead.
Thanks for any and all suggestions!
//-------------------------
using UnityEngine;
using System.Collections;
public class Planet
{
public string name;
public Transform prefab;
public int number;
public Planet(string newName, Transform newPrefab, int newNumber)
{
name = newName;
prefab = newPrefab;
number = newNumber;
}
}
//--------------------------
void Awake()
{
//add to list
planets.Add ( new Planet("Start", start, 1));
planets.Add ( new Planet("End", end, 1));
planets.Add ( new Planet("Merchant", merchant, 1));
planets.Add ( new Planet("Poison", poison, poisonCount));
planets.Add ( new Planet("Repulse", repulse, repulsiveCount));
planets.Add ( new Planet("Money", money, moneyCount));
//Hex Grid spawning
float unitLength = ( useAsInnerCircleRadius )? (radius / (Mathf.Sqrt(3)/2)) : radius;
offsetX = unitLength * Mathf.Sqrt(3);
offsetY = unitLength * 1.5f;
for( int i = 0; i < spawnX; i++ )
{
for( int j = 0; j < spawnY; j++ )
{
Vector2 hexpos = HexOffset( i, j );
Vector3 pos = new Vector3( hexpos.x, hexpos.y, 0 );
if(planets.Count > 0)
Spawn(pos);
}
}
}
void Spawn(Vector3 position)
{
int planet = Random.Range (0, planets.Count);
//if the planet hasn't exceeded its spawn limit, spawn and count down...
if (CheckNumber(planet))
{
Instantiate (planets [planet].prefab, position, Quaternion.identity);
planets [planet].number --;
}
else
planets.Remove(planets[planet]);
}
bool CheckNumber(int index)
{
bool truth = planets[index].number > 0 ? true : false;
return truth;
}
int RandomNumber()
{
int number = Random.Range (0, planets.Count);
return number;
}
Okay, so I recommend that you either have a script that keeps track of the number of times a spawn-point has been use, or have this stored as a public integer (or otherwise have a getter method function that returns this). This counter, either way, should increment every time the GameObject is used to be the spawn-point. I’d put it in its own script just to keep things clean.
Then you have a couple of options (assuming these arrays don’t have to be sorted in any way):
Sort the array every time a spawn-point is discovered to have spawned its limits to reflect this change. You would need to keep track of two integers: one containing the number of “good” spawn-points and one containing the original number.
Remove the GameObject from the array (optionally add it to another, separate array if you want to not destroy it). You would have to check to see if the index in the array points to null whenever you use it, though.
Keep trying to find a spawn-point until you find one that hasn’t reached its maximum count, without removing or sorting anything. This is probably the easiest but the least efficient.
There are more options, but these are the ones that first pop into mind.
To find a random index (to find a random spawn-point) simply use Random.range(0, arraySize - 1);
Here is the basic implementation of the first possible solution (since it might sound a bit weird):
//Variables
bool spawnAvailable = true; //false when the object at index 0 can no longer spawn
bool sortedArray = false;
int limit = 5; //5 spawns per spawner
int SIZE = 10; //array will have 10 elements (indexes 0-9)
int numOfSpawners = SIZE - 1; //a non-const var to keep track of good spawn-points left
int index;
GameObject spawnPointArray;
GameObject bufferObj;
//Spawning
index = Random.range(0, numOfSpawners);
if (spawnAvailable && spawnPointArray[index].GetComponent<SpawnCounterScript>().getSpawnCount() < limit)
{
//spawn from the spawn-point @ this index
}
else if (spawnPointArray[0].GetComponent<SpawnCounterScript>().getSpawnCount() > limit)
spawnAvailable = false;
else
{
while (sortedArray == false)
{
if (spawnPointArray[numOfSpawners].GetComponent<SpawnCounterScript>().getSpawnCount() < limit)
{
bufferObj = spawnPointArray[numOfSpawners];
spawnPointArray[numOfSpawners] = spawnPointArray[index];
spawnPointArray[index] = bufferObj;
sortedArray = true;
}
else
numOfSpawners--;
}
sortedArray = false; //reset variable
index = Random.range(0,numOfSpawners);
//spawn from the spawn-point @ this index
}
I know the sort could be more efficient, but I was making it simple to save space. One thing to note, if you want to access any of the spawners who exceeded the limit, you could get a random index containing one of them (assuming at least one) with Random.range(numOfSpawners, SIZE - 1);
Sorry this post was so long, but I felt complied to provide a code example of what I meant for the first point in case you actually wanted to use it (to provide a guideline). And hopefully I didn’t mess anything up. So if you have any questions (or want to point out any mistakes in something that I totally proof-read…) let me know!