# Impact Random.Range ? Modify probability of outcome ?

Hi guys,
In my game, I’m building a list of items, and then randomly spawn them.
It’s pretty easy to do by generating a random number inside the numbers of items contained in the list and using this rng as the item ID.
But of course that means that every item has the same outcome probability…
You know where I’m going right ?

Is there an elegant way of impacting this probability ? Let’s say I want the item 1 to be spawn 2x more often than the others ?Of course I could duplicate it in the first place and have it 2 times in my list but this seems pretty ugly from a performance standpoint !

Any idea ? Thank you all !

Short answer: f(x) where x is Random.Range and result depends on dispersion you want.

Explanation:
Let’s say we use Random.Range(0f,1f) to get number anywhere from 0 to 1 in float.
To get value int res=0 two times on average when we get value int res=1 one time on average (2:1 proportion) we make

``````int f(float x)
{
if(x<=0.6666)return 0; //item 0
else return 1; //item 1
}

//In code we call it
int randNum = f(Random.Range(0f,1f));
``````

Note: actually it should be 0.(6) in this case so it’ll be slightly lower than 2:1 proportion. You can add more 6 to 0.6666 to get it closer to that exact proportion.

In general case, f(x) can be arbitrary allowing any resulting disperse you want as long as you can find it.
Visually in y=f(x) it’s represented as x being random number generated(all happen with same probability) and y being resulting random number. So you can use any graph drawer to estimate how good this function is for your case.

P.S. don’t forget fs in (0f,1f) - they specify it’s float random, not int. It behaves differently.

Another way to do it:

``````int probability = Random.Range(0, 3);//3 is excluded
switch (probability) {
case 0://33%
case 1://66%
//item 1 chosen
break;
case 2://33%
//item 2 chosen
break;
}
``````

The provided answers require that you specificially hardcode each item. I would try a more general approach where you can define the probability directly in data and let a function pick one. There are some on the Asset Store if you want to pay for it:

If you want to do it yourself just add an int or float value for the relative probability of each item. Then sum up all those values of each item. Then write a function which generates a random number between zero and the sum. Then iterate over the items and “locally” sum the probability up as long as its smaller than the random number. The item where the sum goes above the random number is the desired one.

Example:
Item A Prob 2
Item B Prob 1
Item C Prob 3
Sum = 6
If random number between 0 and 6 (exclusive) = 0 or 1 A is picked (2/6 = 33% chance), if its 2 B is picked (1/6 17% chance) if its 3,4 or 5 C is picked (3/6 50% chance). This is easily extendible when you add more items and does not require code changes. When you display the list you can also calculate the relative probability of each item to ease balancing.

Nope. You can write your own function parser or compile a function and make a function for each random if you do my version with f(x). I didn’t say it needs to be hard-coded.

Your way is of course better in simple cases. But what about distribution for bullets from gun?

Well the most elegant way I can think of doing this is with a normal distribution curve. There isn’t anything built into Mathf, like a Gaussian curve annoyingly… You can get something from the asset store (Unity Asset Store - The Best Assets for Game Making), or there’s examples of it being made here:

http://stackoverflow.com/questions/5817490/implementing-box-mueller-random-number-generator-in-c-sharp

Though I think to be honest that’s overkill for your situation. I’d copy one of the guy’s above examples :).

If you want a curve, just grab an animationCurve, and evaluate it at the time of your random value:

``````public AnimationCurve probCurve; //assign in inspector

public float GetRandomWeighted() {
return probCurve.Evaluate(Random.value);
}
``````

then you can fiddle with your random distribution through fiddling with the curve.

2 Likes

just a big hack, but you could re-purpose the AnimationCurve as a way of graphing out the distribution of random numbers here is a example with floats, but you could just as easily make the tangents hard and parse to int when done for ints.

``````using UnityEngine;

public class RandomTest : MonoBehaviour {
[SerializeField]
private AnimationCurve _curve = new AnimationCurve(new Keyframe(0f, 0f, 0f, 1f), new Keyframe(1f, 1f, 1f, 0f));

private void Update() {
var time = Random.Range(0f, 1f);
var rand = _curve.Evaluate(time);
Debug.Log(rand);
}
}
``````

also keep in mind the anim curve does allow greater than 1 in both time and value, and you can right click a key to give it exact values

Aha! Beat you to it!

1 Like

when you click post it should check if a new post has been made since you started writing your own.