Sunday, October 26, 2008

XNA Series - Modular AI - Flee and Arrival

To continue with our modular AI discussion, we will first look at a "Flee" operation. Fleeing is the opposite of seeking. Rather than turning towards the current position of an object and moving forward, we will turn away from it and move forward. So first we will create a way to turn away from an object. You may remember we had a TurnTowards method, we will copy that method and call it TurnAway and simply make our target rotation Pi Radians (180 degrees) different from the rotation of TurnTowards

public void TurnAway(Vector2 target, float turnSpeed)
{
Vector2 difference = target - position;
float objectRotation = (float)Math.Atan2(difference.Y, difference.X)
+ (float)Math.PI ;
float deltaRotation = MathHelper.WrapAngle(objectRotation - rotation);
rotation += MathHelper.Clamp(deltaRotation, -turnSpeed, turnSpeed);
return;
}

and then we move forward. Since we are doing this as modular as possible, we can reuse the previous Move method.

So our Flee method is simply

public void Flee(Vector2 target, float speed, float turnSpeed)
{
TurnAway(target, turnSpeed);
Move(speed);
}


We also want to implement an "Arrival" behavior. Now so far TurnTowards and TurnAway have effected rotation and Move has effected position. Arrival will effect speed. We will pass Arrival a speed and it will be scaled based on position.

Now target is your target position, speed is your top speed, minDistance is the closest you want to get and maxDistance is the distance where you start slowing down.

public float Arrival(Vector2 target, float speed, float minDist, float maxDist)
{
float dist = Vector2.Distance(position, target);
if (dist > maxDist)
{
return speed;
}
else
{
float percent = (dist - minDist) / (maxDist - minDist);
return MathHelper.SmoothStep(0,speed, percent);
}
}

so we check our distance from the target and if we are outside of slowing range, we just move on ahead otherwise we check what percentage of the slowing range we are then apply smoothstep between our desired speed and 0 using the percent to pick our new speed. Now of course if you have an object with variable speed, you will need to tweak how you use this, but this is bare bones, what can I say. To use this method, I can do this to combine it with Seek

Seek(target, Arrival(target,speed,17,80), turnSpeed);

In the example code, you will see that I injected it into FollowPath to make the tank slow down at each stopping point.


Here are the project files

No comments: