patterncsharpMinor
Video Game AI State Change
Viewed 0 times
videogamechangestate
Problem
I have here a snippet of code from a simple video game AI enemy. The basic idea behind the enemy is that he can be in one of a few states. By default he is in a patrolling state, where he moves around at a slow speed to random points within a circle. While in this state, he is rolling every X seconds to switch to one of his more interesting states. Currently, he may either transition into a state where he spins rapidly while patrolling as stated above, but at a much faster move speed. Or he will can instead go into a stationary defensive spin. Here is the current method which handles this state change:
While this sort of dice rolling method works just fine for now, I can't help but feel that it is more likely to choose the spin attack, since that roll goes first. I can also see this becoming more inefficient if I wanted to add more states for the enemy to transition into. However, I am struggling to come up with a more elegant way to decide which state the enemy should go into.
IEnumerator RollForStateChange()
{
while (true)
{
yield return new WaitForSeconds(RollTickTime);
if (CanRollForStateChange)
{
float spinAttackRoll = Random.Range(0, 100);
if (spinAttackRoll <= SpinAttackChancePerTick)
{
StartCoroutine(SpinAttackTimer());
continue;
}
float spinDefenseRoll = Random.Range(0, 100);
if(spinDefenseRoll <= SpinDefenceChancePerTick)
{
StartCoroutine(DefenseSpinTimer());
continue;
}
}
}
}While this sort of dice rolling method works just fine for now, I can't help but feel that it is more likely to choose the spin attack, since that roll goes first. I can also see this becoming more inefficient if I wanted to add more states for the enemy to transition into. However, I am struggling to come up with a more elegant way to decide which state the enemy should go into.
Solution
You are right that this roll is biased. Instead of using a fixed range and less-than for your rolls, you should just roll once and use specific ranges to choose which action is taken. Something like:
int spinAttackChancePerTickMin = 0;
int spinAttackChancePerTickMax = 50;
int spinDefenceChancePerTickMin = 50;
int spinDefenceChancePerTickMax = 100;
int roll = Random.Range(0, 100);
if (roll >= spinAttackChancePerTickMin &&
roll < spinAttackChancePerTickMax)
{
StartCoroutine(SpinAttackTimer());
continue;
}
StartCoroutine(DefenseSpinTimer());Code Snippets
int spinAttackChancePerTickMin = 0;
int spinAttackChancePerTickMax = 50;
int spinDefenceChancePerTickMin = 50;
int spinDefenceChancePerTickMax = 100;
int roll = Random.Range(0, 100);
if (roll >= spinAttackChancePerTickMin &&
roll < spinAttackChancePerTickMax)
{
StartCoroutine(SpinAttackTimer());
continue;
}
StartCoroutine(DefenseSpinTimer());Context
StackExchange Code Review Q#96161, answer score: 5
Revisions (0)
No revisions yet.