I added context-based steering functionality to my 2d sideview free-roam shoot-'em-up game. Essentially enemy units emit raycasts eventually towards every direction, I determine interest and danger values, calculate the sum total of all vector and move the entity that way.

However, this fails somewhat quickly in the following situation:

Enemy is wandering (there is a position that is essentially its moveTarget, which gives a high interest) around, eventually one of the (8) casts hits the player. The player is a DANGER value so the entity is supposed to move away from the player. A vector is calculated that is essentially a vector opposite the direction to the player, so indeed the entity accelerates AWAY from the player FOR A FRAME. However, next frame, by pure chance, no raycast is hitting the player, so the entity returns to its old course essentially getting close to the player (who sits along its wander target). This happens for 10 or 20 frames, until by pure chance of the 8 casts again hits the player and we again, for a single frame, move away from the player.

How do you solve this? Just tuning up the amount of casts from 8 to 180 would work, but with 16 or 32 casts there will still be plenty of frames when the rays don't hit the player, and hence the entity sees no need to "back off".

  • \$\begingroup\$ Why not keep in memory the result of the last X frames. A risky AI would move towards a reward hit for 5 frames regardless if danger is close or not. A jumpy AI would run away as long as one ray hit a danger in the last X frames. \$\endgroup\$
    – Zibelas
    Jul 19, 2023 at 14:41

1 Answer 1


It sounds like the problem stems from conflicting goals. Specifically, the AI has an attraction toward a goal, a repulsion from the player and trying to resolve the two by moving directly away from the player results in an oscillating behavior.

Abstractly, the solution is to move away from the player in a way that prevents (or at least reduces) the chance that future movements will put the AI back into the same situation. Here are a few ways to could implement this:

After raycasting, select the ray that moves closest to the goal without intersecting the player. This represents a daring or risk taking AI - it will avoid the player to move toward the goal, but it will do as little as possible to avoid the player.

You can make a somewhat more cautious AI by adding a region of avoidance around the player. The AI will do what it can to move toward the goal, but it will skirt further away from the player when doing so. While it's common to use a bounding square or circle for the region of avoidance, it might be worth considering other shapes. For example, if your game physics accounts for momentum, you might bias the avoidance region to be larger in front of the player's direction of travel. The resulting AI would be more likely to attempt to dart just behind the player & less likely to move directly into the player's path. A similar modification could also be made to avoid weapons.

For a very risk averse AI, instead of moving directly away from the player, select an avoidance vector that somewhat less than 180°. This will likely result in some oscillation as the AI may need approach the goal a few times, but by biasing its avoidance off the centerline from the player, it should eventually manage to navigate around the player. Note that while you can randomize the bias, keep in mind that if the bias is too small & changes too frequently, it's more likely to make back to back moves that effectively cancel each other out.

A final observation: any simple steering behavior has limitations. For example, the player could move in a way that herds the AI into some other danger. This isn't necessarily bad from a design perspective though - sometimes part of finding the fun is giving the player opportunities to predict what the AI is likely to do and outsmart the game.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .