Reputation: 1
I want to spawn random prefabs, but I don't want to have any of them coincidentally be identical. I currently have this code block:
int animalIndex = Random.Range(0, 8);
int animalIndex2 = Random.Range(0, 8);
int animalIndex3= Random.Range(0, 8);
int animalIndex4 = Random.Range(0, 8);
int animalIndex5 = Random.Range(0, 8);
int animalIndex6 = Random.Range(0, 8);
// spawn first card
GameObject breeder1 = Instantiate(breedingPhase.randomPrefabs[animalIndex], new Vector3(-4.5f, 3.2f, 0), Quaternion.identity);
// spawn second card
GameObject breeder2 = Instantiate(breedingPhase.randomPrefabs[animalIndex2], new Vector3(0, 3.2f, 0), Quaternion.identity);
// spawn third card
GameObject breeder3 = Instantiate(breedingPhase.randomPrefabs[animalIndex3], new Vector3(4.5f, 3.2f, 0), Quaternion.identity);
// spawn fourth card
GameObject breeder4 = Instantiate(breedingPhase.randomPrefabs[animalIndex4], new Vector3(-4.5f, -2, 0), Quaternion.identity);
// spawn fifth card
GameObject breeder5 = Instantiate(breedingPhase.randomPrefabs[animalIndex5], new Vector3(0, -2, 0), Quaternion.identity);
// spawn sixth card
GameObject breeder6 = Instantiate(breedingPhase.randomPrefabs[animalIndex6], new Vector3(4.5f, -2, 0), Quaternion.identity);
Using the code block above, I can spawn random animals but there are instances where some of them are the same prefab. Thank you in advance for your replies.
Upvotes: 0
Views: 343
Reputation: 2598
Here is a set of functions, SpawnRandomAnimals
, being the entry point.
using System.Linq;
Vector3[] spawnPoints = new Vector3[]
{
new Vector3(-4.5f, 3.2f, 0),
new Vector3(0, 3.2f, 0),
new Vector3(4.5f, 3.2f, 0),
new Vector3(-4.5f, -2, 0),
new Vector3(0, -2, 0),
new Vector3(4.5f, -2, 0)
};
void SpawnRandomAnimals(int numSpawns)
{
int[] indexes = GetIndexesToSpawn(breedingPhase.randomPrefabs, numSpawns);
for (int i = 0; i < indexes.Length; i++)
{
GameObject breeder = Instantiate(breedingPhase.randomPrefabs[indexes[i]], spawnPoints[i], Quaternion.identity);
// ... Do Rest
}
}
void int[] GetIndexesToSpawn(IEnumerable<GameObject> animalCollection, int numSpawns)
{
// Get the number of animals to spawn
int maxAnimals = animalCollection.Count();
int numberToSpawn = numSpawns > maxAnimals ? maxAnimals : numSpawns;
// TODO:
// Find a better way to get spawn point as it currently
// Limits the number of animals we can have.
numberToSpawn = numSpawns > spawnPoints.Length ? spawnPoints.Length : numberToSpawn;
// Create an array of unique indexes to pick from
int[] indexes = CreateArray(numberToSpawn);
// Suffle the indexes
Shuffle(indexes);
// Select the number of spawns
return indexes.Take(numSpawns).ToArray();
}
public int[] CreateArray(int size)
{
if (size < 0)
{
throw new ArgumentException("Size cannot be negative");
}
int[] result = new int[size];
for (int i = 0; i < size; i++)
{
result[i] = i;
}
return result;
}
public void Shuffle(int[] array)
{
int n = array.Length;
for (int i = 0; i < n; i++)
{
// Pick a random index from the remaining unshuffled elements (i to n-1)
int randomIndex = i + rng.Next(n - i);
// Swap element at i with element at randomIndex
int temp = array[i];
array[i] = array[randomIndex];
array[randomIndex] = temp;
}
}
The limitation here is that if you want to spawn 8 animals but only have 6 spawnpoints, only 6 will be spawned. You will need to create a new method for getting spawn points.
Upvotes: 0
Reputation: 1550
You can make a copy of the prefab array and randomly shuffle the elements. Since their order will be random you can simply pick the first, second, etc. element and instantiate it, thus guaranteeing that there will be no duplicates.
The following code shuffles the prefabs by going thru the array element by element and swapping each with another element from the array. An element can also be swapped with itself. I've "lazyfied" your code a little to remove the repetition. It will spawn breeders depending on how many positions are specified.
Vector3[] pos = {new Vector3(-4.5f, 3.2f, 0), new Vector3(0, 3.2f, 0), new Vector3(4.5f, 3.2f, 0), new Vector3(-4.5f, -2, 0), new Vector3(0, -2, 0), new Vector3(4.5f, -2, 0)};
GameObject[] breeder = new GameObject[pos.Length];
//creates new array and shuffles it
GameObject[] shuffledPrefab = breedingPhase.randomPrefabs;
for(int i=0; i<shuffledPrefab.Length; i++){
int element = Random.Range(0, shuffledPrefab.Length);
GameObject temp = shuffledPrefab[i];
shuffledPrefab[i] = shuffledPrefab[element];
shuffledPrefab[element] = temp;
}
//instantiates as many breeders as there are positions
for(int i=0; i<pos.Length; i++){
breeder[i] = Instantiate(shuffledPrefab[i], pos[i], Quaternion.identity);
}
Note that this code will cause an error if you specify more positions than prefabs.
Upvotes: 0