Artificial Life Overview
Artificial life (commonly termed A-life, or just AL) focuses on the behavior of individual creatures that combine into complex patterns, akin to life. The interaction of simple components can spawn incredibly sophisticated simulations.
Steering behaviors are a landmark example in the field, introduced by Craig Reynolds [Reynolds87]. By defining movements in terms of neighboring creatures or the nearby obstacles, we can model complex phenomena—including a flock of birds or even a herd of buffalo. To simulate crowds and realistic creatures in a complex environment, a combination of multiple steering behaviors are used.
The primary building blocks for steering behaviors are presented next; but first, it's important to explain a few lower-level details that the behaviors rely upon.
The steering behaviors assume that there is a lower-level of the engine that takes care of the simulation. This is known as the locomotion of the characters, which includes more than just animation. As expected, each character has a position and a velocity—both handled by the locomotion.
Usually in game environments, significant friction exists. This implies that the velocity diminishes very quickly when the player stops pressing a key. In fact, in many cases, the key presses control the velocity directly—rather than the acceleration.
In the model used by Craig Reynolds's autonomous characters [Reynolds99], the velocity instead persists. The steering forces adjust the velocity. A steering force can be seen as the acceleration applied by the AI. The simulation happens in a standard way for physics simulations (usually Euler integration), except the acceleration and velocity are clipped before they are added to the position. Listing 10.1 shows an algorithm used to update the velocity after a new steering force has been computed.
# make sure the desired steering force isn't too big truncate( steering_force, max_force ) # keep track of the velocity by adding the force velocity += steering_force # apply maximum velocity constraints truncate( velocity, max_speed ) # and use our interfaces to create movement Move( velocity )
From the point of view of the AI, to overcome the friction of the simulation with the existing world interface, we must keep track of the velocity in the AI. This desired velocity is different from the velocity in the physics engine, because it isn't subject to friction.
Another thing to note about the velocity is that it represents the direction of movement. If the characters can turn independently from the movement, their heading will be different from the velocity.
Seeking and Fleeing
Seeking and fleeing are steering behaviors that respectively move toward and away from target locations. If the targets are moving, the analogous behaviors are called pursuit and evasion. The only difference is that we use a prediction of the target position in the future to apply the seek behavior.
The seeking behavior is very simple. The idea is to find a steering force that turns toward the target. Ideally, we would use a velocity that heads straight for the target. By computing this ideal velocity (clipped by the maximum speed), the necessary adjustment is determined relative to the current velocity; this adjustment is used as the steering force. Listing 10.2 shows this computation.The flee behavior is the exact opposite; we just negate the desired velocity. This causes the animat actively to turn away from the target.
The ability to seek is the base of more sophisticated steering behaviors (for instance, path following and flocking). All that is required is a target point; if other behaviors can compute the desired target, seeking can be applied trivially.
# compute the ideal velocity vector towards the target desired_velocity = truncate( position—target, max_speed ) # the steering force is the difference with the current velocity steering_force = desired_velocity—velocity
Because the speed is always set to full, the seek behavior will run through the target point, and oscillate around it. To slow the character down, we need to define a perimeter around the target; outside the perimeter, full speed is used; otherwise, we scale the speed down linearly. Reynolds calls this the arrival behavior.
Other steering behaviors deal with groups of characters. We do not really need the entire set of behaviors to satisfy our requirements. Besides, we're only interested in single animats!
The other steering components (such as alignment and cohesion for modeling flocks) also require a different kind of information; the position and orientation of neighboring creatures are required rather than surrounding obstacles. This implies we need to make small changes in the specification of the input before we can use these other steering behaviors.