This entry is part of 9 in the series Steering Behaviors
Obstacle Avoidance

Avoiding Obstacles, Click to watch.

The next post in the steering behaviors series is obstacle avoidance. We will be using the Vector2D.as and Vehicle.as files for this. If you don’t have them, you should get them. This behavior is based on Craig Reynold’s article Steering Behaviors For Autonomous Characters.

Obstacle Avoidance is used in order to have a vehicle move around an environment without running into objects. This is different from fleeing in one main way. If the vehicle is near a circle and it is not going to hit the circle, nothing is done. If the vehicle was fleeing the circle, it would turn and go directly away from the circle.

Because this isn’t collision detection, we don’t need super accurate shapes to define the obstacles. A bounding circle will be good enough.

Obstacle avoidance is similar to the Ray Casting method, you put out a line and determine if it is touching a circle. If it is, you steer around the circle. You only care about the closest circle. If your ray is long enough that it touches two circles, you only avoid the first one. By avoiding the first one, you are avoiding the second as well.

Now for some code:


private var checkLength:Number = 100;//the distance to look ahead for circles

public function avoidObstacles(circles:Array):void {
for(var i:int = 0; i < circles.length; i++) {//loop through the array of obstacles
var forward:Vector2D = velocity.cloneVector().normalize();//get the forward vector
var diff:Vector2D = circles[i].position.cloneVector().subtract(position);//get the difference between the circle and the vehicle
var dotProd:Number = diff.dotProduct(forward);//get the dot product
//this will be used for projection
//much like in the <a href="http://rocketmandevelopment.com/2010/05/19/separation-of-axis-theorem-for-collision-detection/">SAT</a>

if(dotProd &gt; 0) { //if this object is in front of the vehicle
var ray:Vector2D = forward.cloneVector().multiply(checkLength); //get the ray
var projection:Vector2D = forward.cloneVector().multiply(dotProd); //project the forward vector
var dist:Number = projection.cloneVector().subtract(diff).length; //get the distance between the circle and vehicle

if(dist &lt; circles[i].radius + width &amp;&amp; projection.length &lt; ray.length) {
//if the circle is in your path (radius+width to check the full size of the vehicle)
//projection.length and ray.length make sure you are within the max distance
var force:Vector2D = forward.cloneVector().multiply(maxSpeed); //get the max force
force.angle += diff.sign(velocity) * Math.PI / 2; //rotate it away from the cirlce
//PI / 2 is 90 degrees, vector's angles are in radians
//sign returns whether the vector is to the right or left of the other vector
force.multiply(1 - projection.length / ray.length); //scale the force so that a far off object
//doesn't drastically change the velocity
velocity.add(force);//change the velocity
velocity.multiply(projection.length / ray.length);//and scale again
}
}
}
}

Many vehicles avoiding circles
A vehicle avoiding while chasing the mouse

Sometimes you’ll see problems with warping across the edges. The vehicle can’t look across the edges, so it has no idea a circle is on the edge. It could be fixed, but I’ll leave that to you. Also, on the mouse one, sometimes the seeking behavior is stronger than the avoiding one so you’ll get some odd behavior where the vehicle will get “stuck” on a circle. This could be fixed by weighting the behaviors. We’ll look at this more in later posts.

Series Navigation