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);
    }
}

}

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);
        }
    }
}

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…