There is a bug using for example Random.Range(0, List.Count) that always results 0;
If the list is populated, to say 16; there random range always results 0.
THE SOLUTION???
Well its as simple as var K = List.Count; Random.Range(0,K);
The random range doesn’t seem to like using direct list count references at all.
Random.Range (or any C# method) has no idea if the second argument you passed it came from a local variable or directly from a property on a list. In fact I would be really surprised if the two code examples you posted here didn’t compile down to the exact same IL and machine code. So… I think something else was wrong with your code, and there isn’t actually a bug in Random.Range.
I am generating patterns on a hexagonal grid, at the press of a key.
The patterns use existing coloured hexes in order to decide which tile should be coloured next.
When compiling a list of all of the possible coloured hexes that any given hex could colour next →
Using Random.Range(0,List.Count) to randomly decide which one; only results list index 0. However using the same list count in var k = list.count. results the desired effect.
It could be that the list i use itself, has also been Var’d. i’ve invented it a few seconds(frames) before i filled it. So perhaps that plays a role in the confusion.
Would you mind sharing all of the relevant code in the “non-working” version?
int PlantsToSpawn = 0;
float Pl = Plants.Count; //// This is our primary solution
if (Plants.Count < 1000)
PlantsToSpawn = (int)(Pl * 1.5f) - Plants.Count;
var NewPlants = new List<GameObject>();
Debug.Log(Pl);
if (PlantsToSpawn > 15) // :P :P :P :P
PlantsToSpawn = 15; // Don't Ask, its still WIP
for (int i = 0; i < PlantsToSpawn; i++)
{
int N = (int)Random.Range(0, Pl - 1); // here was the original Plants.Count
if (Plants[N].transform.position != null)
foreach (GameObject Tile in Terrain)
{
if (Tile != null)
{
if (Tile.GetComponent<SpriteRenderer>().color != Water)
{
var D = Vector3.Distance(Plants[N].transform.position, Tile.transform.position);
float Occupied = 0;
foreach (GameObject Plant in Plants)
if (Plant != null)
if (Plant != Plants[N] && Plant.transform.localPosition == Tile.transform.localPosition)
Occupied = Occupied + 1;
if (D < 1 && Occupied < 1)
{
var P = Instantiate(Plants[N], Plants[N].transform.parent);
P.transform.localPosition = Tile.transform.localPosition;
NewPlants.Add(P);
}
}
}
}
}
if (NewPlants.Count > 0)
Plants.AddRange(NewPlants);
Ok so there are actually two versions of Random.Range in unity. You can see both versions here Unity - Scripting API: Random.Range. The first version is the float version, the second version is the int version.
The float version returns a random value from min to max INCLUSIVE. That means if you give it 0 and 2, it can return any number between 0 and 2, INCLUDING 2.
The int version returns a random value from min to max EXCLUSIVE. That means if you give it 0 and 2, it can only return 0 or 1. The main usage of the int version is exactly like you are saying, selecting a random index from an array or list. like this:
List<int> myList = ...
int randomIndex = Random.Range(0, myList.Count);
In your code, notice you are doing this:
float P1 = Plants.Count;
...
int N = (int)Random.Range(0, P1 - 1);
Because P1 is a float, P1 - 1 is a float, and therefore you are using the float version of Random.Range. That’s why you have to subtract the 1 and then cast the result to an int. You will actually not get a uniform distribution this way - I think you will very rarely if ever select the last element from your list because you need to randomly select EXACTLY the last number in the distribution. E.g. if you have 5 elements in the list, you need to randomly get exactly 5. Not 4.9, not 4.996, but only 5 exactly.
This should work just fine for your code to fix it:
int N = Random.Range(0, Plants.Count);
1 Like
Because P1 is a float, P1 - 1 is a float, and therefore you are using the float version of Random.Range. That's why you have to subtract the 1 and then cast the result to an int. You will actually not get a uniform distribution this way - I think you will very rarely if ever select the last element from your list because you need to randomly select EXACTLY the last number in the distribution. E.g. if you have 5 elements in the list, you need to randomly get exactly 5. Not 4.9, not 4.996, but only 5 exactly.
Thanks buddy very detailed and useful information,