8.1.STEERING BEHAVIOUR III
Steering behaviours in game AI
Execution Management
World Interface
Strat
egy
Movem
ent
Animation
Forms of dynamic (or steering) movement algorithm
Physics
targets holds all Objects to consider for separation
Separate( Vector source, Array targets,
float separateThreshold, float separateDecay,
separateThreshold
float maxAcceleration ) {
Separate
The separate behaviour tries to
stop game objects from becoming
too crowded. An accelerative
force is introduced to move away
from any object that is too close.
controls separation
distance drop-off
Vector acceleration = [0,...];
foreach( Object target in targets ) {
Vector direction = target.position - source;
float distance = direction.length();
Determine
separation
strength
if( distance < separateThreshold ) {
float separateStrength =
min( separateDecay * distance * distance,
maxAcceleration );
Update net acceleration
acceleration +=
direction.normalise() * separateStrength;
Individual
repulsion
Individual
repulsion
Net acceleration
Aside: Separate is also known as
the Repulsion Steering behaviour
}
if( acceleration.length() > maxAcceleration )
acceleration =
acceleration.normalise() * maxAcceleration;
return acceleration;
Path following
FollowPath will attempt to steer a
object along some defined path. It is a
delegating behaviour, i.e. a target
position is calculated on which to Seek.
Aside: Arrive may be used to navigate to
the final point (if the path does not loop).
The first step is to determine the
object’s nearest location on the
path (this may be hard). Next, a
target location further along the
path is determined and used as the
Seek target.
Seek output
Closest
path point
Target
path point
Path following (non-predictive)
The basic delegating behaviour
can be defined as:
FollowPath(
path holds the Path object
Object source,
pathOffset controls how
Path path,
far along the path the
float pathOffset ) { target position will be set
Determine the current
position on the path
float pathPosition =
path.getPathPosition(source.position);
float targetPathPosition =
Move along the path
pathPosition
and determine the
+ pathOffset;
world position of
the new path position
Vector target =
path.getPosition( targetPathPosition );
return Seek( source.position, target );
}
Aside: It may be useful to remember
and pass the last path position, i.e.
getPathPosition( Vector currentPosition,
float lastPathPosition) as this can help
to determine the closest path position.
Path following (predictive)
Predictive path following operates
by firstly predicting where the
object will be in a short time and
then mapping this onto the path.
This can result in smoother path
following, but can introduce
skipping when the path points are
close together.
In order to reduce skipping the
last path location can be used to
help determine the correct
position (based on the principle of
coherence)
lookAheadTime controls how far
ahead the position will be predicted
FollowPath( Object source, Path path,
float pathOffset,
lastPathPosition holds
float lookAheadTime, the last determined path
float lastPathPosition ) position
Predict the future location
Vector futurePosition = source.Position +
source.velocity * lookAheadTime;
float pathPosition =
path.getPathPosition(futurePosition,
lastPathPosition);
float targetPathPosition = pathPosition +
pathOffset;
Vector target = path.getPosition(
targetPathPosition );
return Seek( source.position, target );
Path following (predictive problems)
The example below shows a
potential problem with
predictive path-following.
By using the last path position
and the principle of coherence
the skip can be avoided.
Coherent path
locations
Predicted
location
Last path
position
Seek output
Aside: Enforcing
coherence is not
always desirable
(e.g. the object have
may ‘teleported’,
etc.).
Path following (paths)
Different means of defining a path
can be used (including parametric
curve functions).
A list of points provides a
straightforward and effective path
representation. Point spacing can be
varied using the degree of curvature.
The integer path position is defined
as the index of the closest point to
the source.
An array of point-N-to-point-N+1
distances can be maintained to test
for coherence.
Array<Point> pathPoints;
Collision Avoidance
Where there is a lot of
independent game objects
moving in the same space it
will likely be necessary to
provide some form of
collision avoidance.
One approach to collision
avoidance is to trigger an
evade or separate steering
behaviour if a predicted
collision is detected.
Collision Avoidance (collision detection)
A future collision can be detected by
determining the future path of two
objects based on current velocities.
The closest distance of approach can
be calculated and action triggered if
the distance is less than some
threshold (e.g. combined bounding
radii × comfort factor)
Note: The point of closest approach
may not be where the trajectories
cross as different object velocities
may mean objects reach an
intersection point at different times.
Point of closest
approach
Closest
distance
Object 1
Point of
closest
approach
Object 2
Collision Avoidance (collision detection)
The time of closest approach can be
calculated as:
dv
p1
The points of closest approach are
then given by:
v1
dp
v2
p2
Object 1
Object 2
Note: If the time of closest approach is negative
then the objects are moving away from each
other, and no future action is needed.
Collision Avoidance (detection response)
For best results, if a possible collision
has been detected, then the predicted
future locations are used to derive the
evade or separate behaviour (and not
the current positions)
For multiple predicted collisions, the
object with the closest predicted time
of collision should be reacted to first.
Note: If the point of collision will occur at
the centre of both objects (unlikely, but
maybe possible) then evade, etc. will be
unable to operate. A special case would
be needed to handle this situation, e.g.
evading on the current positions, etc.
Collision Avoidance
targets holds all Objects to consider for avoidance
CollisionAvoidance(
Object source, Array targets) {
Object closestTarget = null;
float closestTime = float.max;
float closestSep, closestDis;
// Determine closest target
foreach( Object target in targets ) {
Vector relPos =
target.position – source.position;
Vector relVel =
target.velocity – source.velocity;
float relSpeed = relVel.length();
float relDistance = relPos.length();
If already in
collision, or
exact centre hit
then steer away
from current
position, else
use predicted
location.
if( closestTarget == null ) return;
if( closestSep <= 0 || closestDis <
source.radius + closestTarget.radius )
return Evade( source.position,...);
else {
return Evade( source.position +
source.velocity * closestTime, ... );
}
Determine time to collide
using provided formula
float timeToCollide
= Math.dot(relPos, relVel)
/ (relSpeed * relSpeed );
If collision detected and
closest so far, then store
float minSep =
relDistance – relSpeed * closestTime;
if( minSep < source.radius + target.radius )
if( timeToCollide > 0 AND
timeToCollide < closestTime ) {
// Store closestTarget, closestTime, ...
}
}
Collision Avoidance (walls and large objects)
The previous algorithm assumes a
circular/spherical bound (applicable
to lots of objects).
For large irregular objects or
rectangular objects (e.g. walls) a
bounding sphere can offer a poor
bound (a large volume around the
object will be needlessly avoided).
Collision Avoidance (walls and large objects)
A suitable approach for walls,
etc. involves casting one or
more rays in the direction of
travel. The rays will have a
defined maximum length.
If the rays collide with an object
then a movement target is
created to avoid the collision,
and a Seek made towards the
target.
Cast ray
Point of collision
Normal to collision
Seek target to
avoid collision
Collision Avoidance (walls and large objects)
ObstacleAvoidance(
Object source, CollisionDetector detector ) {
float avoidDistance;
float lookaheadDistance;
Vector ray = source.velocity;
ray.normalize();
ray *= lookaheadDistance;
A CollisionDetector is assumed to be an object that
has awareness of the level geometry and can test
for object/ray intersection – returning at least an
intersection point and normal vector.
CollisionInfo is
assumed to hold
information on
any detected
collision(s).
CollisionInfo collision = detector.getCollision(
source.position, ray)
if( collision == null ) return;
Vector targetPosition = collision.position
+ collision.normal * avoidDistance;
return Seek( source.position,
targetPosition )
Note: Developing a fast and efficient
collision detection system can be a
sizeable undertaking. For more
information see:
http://en.wikipedia.org/wiki/Collision_detection
http://www.realtimerendering.com/intersections.html
Collision Avoidance (walls and large objects)
Collision not
detected
A single cast ray may not avoid an
obstacle as shown opposite.
Other common configurations
include:
Corner trap – collision
avoidance cancels out
• Parallel side rays – good for tight
passages, susceptible to the corner
trap.
• Central ray with short whiskers –
need to cast three rays, not good for
very tight passages.
• Whiskers only – ‘blind spot’ close to
object, not good for tight passages
Parallel
side rays
Central
ray, side
whiskers
Whiskers
Constrained movement (motor control)
Steering behaviours provide movement
requests, i.e. acceleration vector.
Some objects may not be able to
immediately realise the request, e.g. a
car can only accelerate
forward/backward (with different rates)
and has a turning rate that varies with
movement speed, i.e. different objects
can have different behaviours.
In order to realise movement requests,
a motor control layer can determine
how best to execute a request, a
process known as actuation.
Constrained movement (filtering)
The simplest actuation approach is to
remove all components of the steering
output that cannot be currently
realised.
Running the filtering algorithm every
update tick (the steering output may
remain constant) the object will move
to match the steering target.
This approach is easily implemented,
fast and reasonably effective,
however, it can result in much smaller
than requested accelerations (which
can be detected and avoided if
desired).
Achievable linear
and angular
acceleration
Requested
angular
acceleration
Requested
linear
acceleration
Constrained movement (cars and bikes)
Vehicular movement can be constrained
using decision arcs.
A forward arc in which the vehicle will turn
towards the target without braking.
Front arc
Rear arc
Maximum
reversing
distance
A rear arc (with a maximum range) in which
the car will reverse towards the target.
The arcs shrink based on movement speed
and amount of grip. At low speeds the
forward and rear arc must touch (to prevent
breaking deadlock at low speed).
If the target lies between the two arcs, then
the vehicle will break and turn towards the
target.
Breaking arc
Front
arc
Rear
arc
Breaking arc
Summary
Today we
explored:
More
advanced
steering
behaviours
including path
traversal and
collision
avoidance
Constrained
movement
using
actuation
© Copyright 2026 Paperzz