how to randomly instantiate prefabs but each with it's own probability?
I'm building a space shooter game and throughout the game I want to randomly instantiate 10 items but each with it's own probability, such that items with the most significance will show up the least and those with least impact would show up the most. so far I'm thinking about using Random.Range(0,101); and using if statements in such a way: 0-10 item 1 =10% probability 10-20 item2=10% 20-25 item3 =5%
is this a good way? or is there a better way ?
Answer by noppander · Oct 12, 2016 at 04:29 PM
Hi @SuperRaed
Hopefully you have figured this out and in that case I would like to hear what you did and how did you get it done, but here is the case I am having for those still struggling:
I have a game which creates a randomly generated pathway with different kind of "Block Sets" and variations. The way you described was the way i did this first, but if you need to add new prefabs to the pool, it gets frustrating really quickly.
So the solution i figured out was this [simplified]
I have two arrays:
Public Gameobject[] prefabArray; // 1. The prefabs to be instantiated
Public int[] chanceArray; // 2. The percentages of these prefabs
Before the user (developer) can run the script, he needs to set up Public List which contains all the prefabs.
Chance array needs to have manually set as the same length as prefabArray. Being a public array, all the chance values are shown (and editable) in the editor inspector.
All the values in prefabChances array are combined and if it's not 100 the user will be prompted to re-enter them or possibly the numbers will be fixed through script.
When we have the chance values, I have one random value between 0 - 100 (doing it between 1-101 is possible also, but the first value for coders in an array is 0). If we have five 20% values in our 100% pool, the random value will hit one of the prefabs as described below:
You can use a char array of 100 or just check the value through switch case or if statements.
Random value: 45
A = 0 -19
B = 20 - 39
C = 40 - 59
D = 60 - 79
E = 80 - 99
45 = C
You need to set these values every time you add a new prefab to the pool, but this can be automated (By randomizing the chance values) and when you are ready and you know there will be no more prefabs to this pool, set the values, tweak and use them.
Provided by: Noppa
PS. If you found this information useful, upvote to let me and others know.
Answer by ecreators · Nov 18, 2020 at 03:13 PM
Hi @SuperRaed,
I figured out another solution, that helped me very much.
Explanation for my solution
Instead of using percentages, I suggest using integers. It is more readable.
For example
In case of 3 items to spawn with own chances
Item A with a chance of 5 of 10 possibilities.
Item B with a chance of 3.
Item C with a chance of remaining 10 - 5 - 3 = 2 (chance).
Fill their indices into a pool array or list with their amount of absolute chances.
In that example, it will produce a pool of indices like [0,0,0,0,0,1,1,1,2,2] like 5 times Index zero, 3 times Index one, 2 times Index two. I used this solution because I wanted to have a pool of chances, I want to select from. So why not do it like that.
Now I shuffled that pool with indices.
At end I used a random index for that size of pool list.
In this example, item A has a chance of 5 to 10 to be selected, item B a chance of 3 and item C a chance of 2 to be selected.
[Serializable]
public class Spawnable
{
public int chanceOf10 = 10;
public GameObject spawnPrefab;
}
public Spawnable[] creatableContent;
private Spawnable GetRandomSpawnable()
{
var pool = new List<int>();
FillPool(creatableContent, pool);
pool.Shuffle();
int index = Random.Range(0, pool.Count - 1);
int spawnableIndex = pool[index];
Spawnable spawnablePrefab = creatableContent[spawnableIndex];
return spawnablePrefab;
}
private void FillPool(Spawnable[] creatableContent, List<int> spawnablesIndices)
{
for (int indexOfSpawnable = 0; indexOfSpawnable < creatableContent.Length; indexOfSpawnable++)
{
Spawnable spawnable = creatableContent[indexOfSpawnable];
for (int j = 0; j < spawnable.chanceOf10; j++)
{
spawnablesIndices.Add(indexOfSpawnable);
}
}
}
If required, my code for shuffle a list
public static class CSharpExtensions
{
private static readonly Random random = new Random(Guid.NewGuid().GetHashCode());
/// <summary>
/// Puts each entry to another index
/// </summary>
public static void Shuffle<T>(this IList<T> list)
{
for (int i = 0; i < list.Count; i++)
{
var newIndex = random.Next(0, list.Count - 1);
T a = list[i];
T b = list[newIndex];
list[newIndex] = a;
list[i] = b;
}
}
}
Your answer
Follow this Question
Related Questions
random question without repetition 0 Answers
Random Scenes Without Repetition 1 Answer
Can no1 help me??? 1 Answer
How to generate a random color? 5 Answers