The question is answered, right answer was accepted
Random Range Without Duplicates
,Hi, I need a little help regarding Random.Range returning duplicates.
In the below code I have two arrays:
public GameObject[] powerupPrefab; public Transform[] powerupSpawnPoint;
The intention is that the length of my powerupSpawnPoint array is the maximum number of spawnpoints (This is working as intended)
However I do not want my gameobjects to spawn on top of one another, so although I need the return to be random it cannot be a duplicate as each index must be unique,
The problem is that Random Range will return duplicate indexes such as 0, 1, 1 and then only two of my potential three spawn points were used
here is the code in full
public class PowerupSpawner : NetworkBehaviour {
public GameObject[] powerupPrefab;
public Transform[] powerupSpawnPoint;
public override void OnStartServer()
{
for (int i = 0; i < powerupSpawnPoint.Length; i++)
{
int spawnIndex = Random.Range(0, powerupSpawnPoint.Length);
int prefabIndex = Random.Range(0, powerupPrefab.Length);
GameObject powerup = (GameObject)Instantiate(powerupPrefab[prefabIndex], powerupSpawnPoint[spawnIndex].position, powerupSpawnPoint[spawnIndex].rotation);
NetworkServer.Spawn(powerup);
}
}
}
Answer by villevli · Jan 24, 2018 at 10:47 PM
I would use a List like this.
public class PowerupSpawner : NetworkBehaviour
{
public GameObject[] powerupPrefab;
public Transform[] powerupSpawnPoint;
public override void OnStartServer()
{
List<Transform> remainingSpawnPoints = new List<Transform>(powerupSpawnPoint);
for (int i = 0; i < powerupSpawnPoint.Length; i++)
{
int spawnPointIndex = Random.Range(0, remainingSpawnPoints.Count);
int prefabIndex = Random.Range(0, powerupPrefab.Length);
GameObject powerup = (GameObject)Instantiate(powerupPrefab[prefabIndex], remainingSpawnPoints[spawnPointIndex].position, remainingSpawnPoints[spawnPointIndex].rotation);
NetworkServer.Spawn(powerup);
remainingSpawnPoints.RemoveAt(spawnPointIndex);
}
}
}
Answer by Honorsoft · Jan 24, 2018 at 10:59 PM
I used to remember how to do that. It was basic C++ practice (sorting, shuffling, etc). There are always many ways to do it, and I'm sure someone will post a better method using some sort of built-in Unity function, but just to hold you over.. To the best of my memory, one time I needed a random enemy to spawn, but each enemy was unique and therefore I did not want two of the same enemy spawning, So I just used an array of the enemies, each holding the value of 1 or 0 (whether they had been spawned or not). Kind of like this:
//pseudo code (just example code, dynamic arrays are so nice...)
//Initialize
array Enemy[]; //make an array
int enemyNum = 3; //Game has 4 different enemies (0,1,2,3)
//Start
for (i = 0 to enemyNum) {Enemy[enemyNum] = 0;} //set all the enemies to 'not chosen'
eg, Enemy[0]=0;Enemy[1]=0;Enemy[2]=0; etc.
//Spawn function
When an enemy is randomly picked set it's corresponding array 'marker' to 1 (spawned already).
eg
// 1st, start a While loop (While 'none chosen')
// 2nd, pick a random number then check if corresponding enemy has already been spawned
While (Enemy[spawnedEnemy] = 0)
{
int spawnedEnemy = Random(range: 0 to enemyNum)
// int spawnedEnemy now equals 3 for example
if (Enemy[spawnedEnemy] = 0) // if Enemy[3] hasn't been spawned yet
{Enemy[spawnedEnemy] = 1;Spawn(Enemy[spawnedEnemy]);} //set the 'flag' and spawn the enemy object
} //end of While loop
Now whenever you call the custom Spawn() function you make, it should keep While-looping until it finds an enemy not spawned yet, then spawn that enemy and set it's Enemy[#] to 1
Hope that's not confusing, I tried to explain the logic and not the code...
Follow this Question
Related Questions
List or Arrays, and how to randomize them. 1 Answer
Spawn unique objects from the array 1 Answer
How do you spawn a gameobject based on last object in array and limit that within a range? 1 Answer
Use all variables from array (in Random.Range()) 2 Answers
C# Having troubles with creating/referencing a random list. 1 Answer