Read Foundation Game Design with ActionScript 3.0, Second Edition Online
Authors: Rex van der Spuy
After the bee knows what its target is (the mouse), it calculates the distance between itself and the target. If the distance is less than theRANGE
value (which is 200), the bee moves.
It moves using a variation of the easing formula we looked at earlier in the chapter. It's a little more complex, however, because you want to limit the bee's speed and the rate at which it turns. Here are the steps the code takes and the formulas it uses to accomplish each task:
move_X
andmove_Y
variables:var move_X:Number = TURN_SPEED * vx / distance;
var move_Y:Number = TURN_SPEED * vy / distance;
_bee.vx += move_X;
_bee.vy += move_Y;
var moveDistance:Number
= Math.sqrt(_bee.vx * _bee.vx + _bee.vy * _bee.vy);
SPEED
constant to find the correct velocity:_bee.vx = SPEED * _bee.vx / moveDistance;
_bee.vy = SPEED * _bee.vy / moveDistance;
This is a variation of our easing formula, withSPEED
representing the easing value.
_bee.rotation = Math.atan2(_bee.vy, _bee.vx) * 180 / Math.PI + 90;
If the target is
not
within the bee's range, the following directives kick in, which gradually slow the bee down by using friction:
//Apply friction
_bee.vx *= FRICTION;
_bee.vy *= FRICTION;
//Move the bee
_bee.x += _bee.vx;
_bee.y += _bee.vy;
A bit of simple logic, a few careful adjustments to the easing formula, and you have a very effective following behavior.
It's very easy to create the exact opposite behavior to make the bee run away from the mouse. To see this at work, open the RunAway project folder and run the SWF. You'll see the bee flee from the mouse, as illustrated in
Figure 10-9
.
When I say that this is the opposite behavior, I mean that in the most literal sense imaginable. The application class is exactly the same as the in the previous case, except that the three plus signs have been made negative.
The bee's rotation is negative so that it points in the opposite direction, like so:
_bee.rotation
= 180 * Math.atan2(_bee.vy, _bee.vx) / Math.PI - 90;
The velocity is also negative, as you can see here:
_bee.x -= _bee.vx;
_bee.y -= _bee.vy;
That's it!
Figure 10-9.
Get too close and the bee flies away.
In the final AI system, the bee turns and fires bullets toward the mouse if the mouse is within range. You'll find this example in the RotateAndShoot project folder, and
Figure 10-10
shows what you'll see when you run the SWF file.
Figure 10-10.
The bee flies toward the mouse and fires bullets at it.
The code that does this is a fusion of the Follow example, with the addition of a bullet-firing system. The bullets are fired using a timer that's started when the mouse comes within range of the bee. Here's the application class that makes this work:
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
import flash.events.TimerEvent;
import flash.utils.Timer;
[SWF(width="550", height="400",
backgroundColor="#FFFFFF", frameRate="60")]
public class RotateAndShoot extends Sprite
{
//Embed the images
[Embed(source="../images/bee.png")]
private var BeeImage:Class;
[Embed(source="../images/bullet.png")]
private var BulletImage:Class;
//Properties
private const SPEED:Number = 3;
private const TURN_SPEED:Number = 0.3;
private const RANGE:Number = 200;
private const FRICTION:Number = 0.96;
private var _beeImage:DisplayObject = new BeeImage();
private var _bee:GameObject = new GameObject(_beeImage);
//The bee's angle of rotation
private var _beeAngle:Number;
//A timer to fire bullets
private var _bulletTimer:Timer;
//An array to store the bullets
private var _bullets:Array = new Array();
public function RotateAndShoot()
{
//Add the bee to the stage
stage.addChild(_bee);
_bee.x = 275;
_bee.y = 175;
//Initialize the timer
_bulletTimer = new Timer(1000);
_bulletTimer.addEventListener
(TimerEvent.TIMER, bulletTimerHandler);
//Add the event listeners
stage.addEventListener
(Event.ENTER_FRAME, enterFrameHandler);
}
private function bulletTimerHandler(event:TimerEvent):void
{
//Create a bullet and add it to the stage
var bulletImage:DisplayObject = new BulletImage();
var bullet:GameObject = new GameObject(bulletImage);
stage.addChild(bullet);
//Set the bullet's starting position
var radius:int = 30;
bullet.x = _bee.x + (radius * Math.cos(_beeAngle));
bullet.y = _bee.y + (radius * Math.sin(_beeAngle));
//Set the bullet's velocity based the angle
bullet.vx = Math.cos(_beeAngle) * 2 + _bee.vx;
bullet.vy = Math.sin(_beeAngle) * 2 + _bee.vy;
//Push the bullet into the _bullets array
_bullets.push(bullet);
}
private function enterFrameHandler(event:Event):void
{
//Get the target object
var target_X:Number = stage.mouseX;
var target_Y:Number = stage.mouseY;
//Calculate the distance between the target and the bee
var vx:Number = target_X - _bee.x;
var vy:Number = target_Y - _bee.y;
var distance:Number = Math.sqrt(vx * vx + vy * vy);
if (distance <= RANGE)
{
//Find out how much to move
var move_X:Number = TURN_SPEED * vx / distance;
var move_Y:Number = TURN_SPEED * vy / distance;
//Increase the bee's velocity
_bee.vx += move_X;
_bee.vy += move_Y;
//Find the total distance to move
var moveDistance:Number
= Math.sqrt(_bee.vx * _bee.vx + _bee.vy * _bee.vy);
//Apply easing
_bee.vx = SPEED * _bee.vx / moveDistance;
_bee.vy = SPEED * _bee.vy / moveDistance;
//Rotate towards the bee towards the target
//Find the angle in radians
_beeAngle = Math.atan2(_bee.vy, _bee.vx);
//Convert the radians to degrees to rotate the bee correctly
_bee.rotation = _beeAngle * 180 / Math.PI + 90;
//Start the bullet timer
_bulletTimer.start();
}
else
{
_bulletTimer.stop();
}
//Apply friction
_bee.vx *= FRICTION;
_bee.vy *= FRICTION;
//Move the bee
_bee.x += _bee.vx;
_bee.y += _bee.vy;
//Move the bullets
for(var i:int = 0; i < _bullets.length; i++)
{
var bullet:GameObject = _bullets[i];
bullet.x += bullet.vx;
bullet.y += bullet.vy;
//check the bullet's stage boundaries
if (bullet.y < 0
|| bullet.x < 0
|| bullet.x > stage.stageWidth
|| bullet.y > stage.stageHeight)
{
//Remove the bullet from the stage
stage.removeChild(bullet);
bullet = null;
_bullets.splice(i,1);
i--;
}
}
}
}
}
A timer is set up to fire bullets every second if the mouse is within range of the bee. The timer is started if it's within range, and stopped if it's out of range, as you can see in the following abridged code from theenterFrameHandler
:
if (distance <= RANGE)
{
//…
_bulletTimer.start();
}
else
{
_bulletTimer.stop();
}
TheenterFrameHandler
then loops through all the bullets in the_bullets
array to move them, and removes them from the game if they cross the stage boundaries.
There's one small modification you can make that will make the bee's shooting behavior much more realistic. As it's been coded, the bee shoots right on cue every 1,000 milliseconds. You can use theTimer
class'sdelay
property to randomize this. Add the following highlighted code to thebulletTimerHandler
event handler to see the effect:
private function bulletTimerHandler(event:TimerEvent):void
{
var bulletImage:DisplayObject = new BulletImage();
var bullet:GameObject = new GameObject(bulletImage);
stage.addChild(bullet);
var radius:int = 30;
bullet.x = _bee.x + (radius * Math.cos(_beeAngle));
bullet.y = _bee.y + (radius * Math.sin(_beeAngle));
bullet.vx = Math.cos(_beeAngle) * 2 + _bee.vx;
bullet.vy = Math.sin(_beeAngle) * 2 + _bee.vy;
_bullets.push(bullet);
//Find a random start time for the next bullet
var randomFireTime:Number
= Math.round(Math.random() * 1000) + 200;
_bulletTimer.delay = randomFireTime;
}
The bee now fires randomly between 200 and 1,200 milliseconds.
This AI system is at the heart of what you need to know if you want to create any kind of rotating enemy gun turret for your games. Just substitute another game object for the mouse, and the bee will chase and fire at the object, as we'll see in the next example.
We've made a lot of fun little toys in this chapter, and it doesn't take much work to turn them into a real game. What would happen if we put Button Fairy in the same environment as Killer Bee? We'd get an all-out power shootout between two arch enemies in Killer Bee Pandemonium!, which you'll find in the source files. Run the SWF file and play the game, which you can see in
Figure 10-11
.
Figure 10-11.
Can Button Fairy save the woodland creatures from the grumpy Killer Bee?