I’m writing a character wander function. The character should decide to randomly wander into a neighbouring tile or not. (its a tile based game). I started with this in his Update() function
if (Random.Range(0f,1f) > 0.95f) {
StartWander()
}
However, that breaks horribly when the framerate is lower as there are much fewer calls to Update() and the chances of a wander drop.
I want the wander to be Random, but the same chance regardless of framerate. So i need to incorporate deltaTime but I’m lost as to the correct math and my googling didnt find an answer.
Are you sure you need to call the random test every frame (Update()) or even more often (FixedUpdate())?
It seems, a Coroutine would work:
const float checkTime = .5f; // adjust this parameter to check more/less frequently
bool wandering = false;
IEnumerator CheckStartWandering() {
while(!wandering) {
yield return new WaitForSeconds(checkTime);
if (Random.Range(0f,1f) > 0.95f) {
StartWander();
}
}
}
StartWander() should set
wandering = true;
, so the random test stops when wandering. You should call
StartCoroutine(CheckStartWandering());
at Start() and/or whenever after one “Wandering-Process” the check should be enabled agin.
With this, you check in fixed intervals, but not excessively often (as in FixedUpdate()).
Depending on the circumstances, it might be more optimal to only use one Coroutine (and not starting one each time as suggested in my code above) - but I would not worry about that for now, until there are any performance problems.
Another way is to use “math” to calculate the required probability for each frame to get an average target probability for example per second.
To calculate the average probability (P(A)) that an event happens at least once, given a per-event-probability (P(E)) and the number of events (n) is this:
P(A) = 1 - ((1 - P(E))^n)
Since we want the reverse, i.e. calculating what probability we have to use for each event to get a certain average probability we have to reverse the formula:
P(E) = 1-((1- P(A))^(1/n))
So we basically have to take the n-th root of the complement of the average probabilty.
For example if you want a 20% chance every second you would do:
Note that this only gives you a statistical chance. It’s still random so it can even happen 5 times in a row each frame. That case is very unlikely put possible. In most cases you don’t want / need to change the direction that frequently. So using a coroutine with a low execution rate (like @jwulf suggested) is probably the better solution. I would not recommend to use FixedUpdate as it is related to the physics system and should only be used for that. If you need a custom fixed update method you can use this class i created. It does the same as Unity does for FixedUpdate but allows you to have as many independent fixed update methods as you want.
Just for completeness, here’s an actual implementation in Unity: