Read Foundation Game Design with ActionScript 3.0, Second Edition Online
Authors: Rex van der Spuy
Button Fairy can fly around the screen and shoot the bee. The Killer Bee flies toward her and fires bullets if she's within range. The scoreboards at the top of the stage keep track of the number of hits each has achieved.
All the objects in the game are made using the generalGameObject
class, so there are no custom classes to keep track of. That keeps the game structure and code really simple, and you can find out everything you need to know about how the game works just by looking at the application class. The application class doesn't contain any new code at all; it's just an everything-but-the-kitchen-sink example using most of the code we've already covered in this chapter. The one thing to keep an eye on, however, is the loops that move the star and bullet projectiles and check them for collisions. The loops have to make sure that they don't check for collisions with projectiles that they've already removed. We'll take a closer look at how this works ahead.
Here's theKillerBeePandemonium
application class. You'll see that all the sections of code that move the different kinds of objects are in their own methods. Each of these methods is being called by theenterFrameHandler
. This is just to help organize the code so that it's easier to find and work with these different sections.
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.text.*;
import flash.ui.Mouse;
import flash.utils.Timer;
[SWF(width="800", height="600",
backgroundColor="#FFFFFF", frameRate="60")]
public class KillerBeePandemonium extends Sprite
{
//The images
[Embed(source="../images/fairy.png")]
private var FairyImage:Class;
[Embed(source="../images/wand.png")]
private var WandImage:Class;
[Embed(source="../images/star.png")]
private var StarImage:Class;
[Embed(source="../images/background.png")]
private var BackgroundImage:Class;
[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 = 500;
private const FRICTION:Number = 0.96;
private const EASING:Number = 0.1;
private var _fairyImage:DisplayObject = new FairyImage();
private var _wandImage:DisplayObject = new WandImage();
private var _backgroundImage:DisplayObject
= new BackgroundImage();
private var _beeImage:DisplayObject = new BeeImage();
private var _fairy:GameObject = new GameObject(_fairyImage);
private var _wand:GameObject = new GameObject(_wandImage);
private var _bee:GameObject = new GameObject(_beeImage);
private var _background:GameObject
= new GameObject(_backgroundImage, false);
private var _angle:Number;
private var _beeAngle:Number;
private var _stars:Array = new Array();
private var _bullets:Array = new Array();
private var _bulletTimer:Timer;
private var _format:TextFormat = new TextFormat();
private var _fairyScoreDisplay:TextField = new TextField();
private var _beeScoreDisplay:TextField = new TextField();
private var _fairyScore:int;
private var _beeScore:int;
public function KillerBeePandemonium()
{
//Add game the objects
stage.addChild(_background);
setupTextFields();
stage.addChild(_fairy);
stage.addChild(_wand);
stage.addChild(_bee);
_bee.x = 275;
_bee.y = 175;
//Initialize the timer
_bulletTimer = new Timer(500);
_bulletTimer.addEventListener
(TimerEvent.TIMER, bulletTimerHandler);
//Hide the mouse
Mouse.hide();
//Add the event listeners
stage.addEventListener
(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener
(MouseEvent.MOUSE_DOWN, mouseDownHandler);
}
private function setupTextFields():void
{
//Set the text format object
_format.font = "Helvetica";
_format.size = 44;
_format.color = 0x000000;
_format.align = TextFormatAlign.CENTER;
//Configure the fairy's score text field
_fairyScoreDisplay.defaultTextFormat = _format;
_fairyScoreDisplay.autoSize = TextFieldAutoSize.CENTER;
_fairyScoreDisplay.border = false;
_fairyScoreDisplay.text = "0";
//Display and position the fairy's score text field
stage.addChild(_fairyScoreDisplay);
_fairyScoreDisplay.x = 180;
_fairyScoreDisplay.y = 21;
//Configure the bee's score text field
_beeScoreDisplay.defaultTextFormat = _format;
_beeScoreDisplay.autoSize = TextFieldAutoSize.CENTER;
_beeScoreDisplay.border = false;
_beeScoreDisplay.text = "0";
//Display and position the bee's score text field
stage.addChild(_beeScoreDisplay);
_beeScoreDisplay.x = 550;
_beeScoreDisplay.y = 21;
}
private function enterFrameHandler(event:Event):void
{
moveFairy();
moveBee();
moveStars();
moveBullets();
}
private function moveBullets():void
{
//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--;
}
//Check for a collision with the fairy
if(bullet != null
&& bullet.hitTestObject(_fairy))
{
//Update the score, the score display
//and remove the bullet
_beeScore++;
_beeScoreDisplay.text = String(_beeScore);
stage.removeChild(bullet);
bullet = null;
_bullets.splice(i,1);
i--;
}
}
}
private function moveStars():void
{
//Move the stars
for(var i:int = 0; i < _stars.length; i++)
{
var star:GameObject = _stars[i];
star.x += star.vx;
star.y += star.vy;
//check the star's stage boundaries
if (star.y < 0
|| star.x < 0
|| star.x > stage.stageWidth
|| star.y > stage.stageHeight)
{
//Remove the star from the stage
stage.removeChild(star);
star = null;
_stars.splice(i,1);
i--;
}
//Check for a collision with the bee
if(star != null
&& star.hitTestObject(_bee))
{
//Update the score, the score display
//and remove the bullet
_fairyScore++;
_fairyScoreDisplay.text = String(_fairyScore);
stage.removeChild(star);
star = null;
_stars.splice(i,1);
i--;
}
}
}
private function moveBee():void
{
//Get the target object
var target_X:Number = _fairy.x;
var target_Y:Number = _fairy.y;
//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;
}
private function moveFairy():void
{
//Find the angle between the center of the
//fairy and the mouse
_angle
= Math.atan2
(
_fairy.y - stage.mouseY,
_fairy.x - stage.mouseX
);
//Move the wand around the fairy
var radius:int = -50;
_wand.x = _fairy.x + (radius * Math.cos(_angle));
_wand.y = _fairy.y + (radius * Math.sin(_angle));
//Figure out the distance between the
//mouse and the center of the fairy
var vx:Number = stage.mouseX - _fairy.x;
var vy:Number = stage.mouseY - _fairy.y;
var distance:Number = Math.sqrt(vx * vx + vy * vy);
//Move the fairy if it's more than 1 pixel away from the mouse
if (distance >= 1)
{
_fairy.x += vx * EASING;
_fairy.y += vy * EASING;
}
}
//Let the bee fire bullets using a timer
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 on the angle
bullet.vx = Math.cos(_beeAngle) * 5 + _bee.vx;
bullet.vy = Math.sin(_beeAngle) * 5 + _bee.vy;
//Push the bullet into the _bullets array
_bullets.push(bullet);
//Find a random start time for the next bullet
var randomFireTime:Number
= Math.round(Math.random() * 1000) + 200;
_bulletTimer.delay = randomFireTime;
}
//Let Button Fairy fire stars when the mouse is clicked
private function mouseDownHandler(event:MouseEvent):void
{
//Create a star and add it to the stage
var starImage:DisplayObject = new StarImage();
var star:GameObject = new GameObject(starImage);
stage.addChild(star);
//Set the star's starting position
//to the wand's position
star.x = _wand.x;
star.y = _wand.y;
//Set the star's velocity based
//on the angle between the center of
//the fairy and the mouse
star.vx = Math.cos(_angle) * -7;
star.vy = Math.sin(_angle) * -7;
//Push the star into the _stars array
_stars.push(star);
}
}
}
As I mentioned, the important thing to keep aware of in this code is that the loops that check for collisions between the projectiles and the game objects have to make sure that the projectile hasn't already been removed from the game earlier, if it had crossed a stage boundary. That's why theif
statement that checks for a collision also has to make sure that the object isn'tnull
.
if(bullet != null
&& bullet.hitTestObject(_fairy))
{…
This is just a small technical detail to take care of, but will ensure that your game doesn't generate any runtime errors while it's playing.
Most of this book has been about writing the computer code you need to know to make video games. That's been the hardest part, but there's much more that you can and should do with your games besides just program them. How can you easily create animated objects for your games, and how can you publish your game after you've created it? You'll find out how to do both these things in the bonus chapter “Flash
Animation and Publishing Your Game” that you'll find in the book's download package. You'll learn how to use Flash Professional software to quickly make game animations that you can control using AS3.0 code. In addition, if you want to make games for mobile phones and tablets, you'll find out how to use Flash Builder to publish your games to those platforms.
Hey, is the book finished already? It is, but it seemed like all the fun was only just starting! If you've reached this last section in the book, congratulate yourself: You're a game designer! With the skills you've acquired throughout this book, there are few game design scenarios that you won't be able to approach with confidence.
However, if you're like everyone else who's ever started learning game design, you'll find that the desire to learn more is insatiable. Although you've accomplished so much already, there's a great universe of learning ahead of you. Here's a quick roundup of some of the areas you might want to explore:
www.adobe.com/devnet/actionscript.html
. There you'll find links to the ActionScript 3 Developer's Guide and ActionScript 3 Reference for the Flash Platform. I've made numerous references to sections of these documents throughout this book, and they remain the most comprehensive primary source for all things Flash and AS3.0. Although many of the topics they deal with and the approaches they take are reasonably advanced, they should match your current level of ability. Spend some time going through some of the hundreds of articles and you're sure to find great food to fuel your developing programming skills.www.adobe.com/devnet/flashplayer/stage3d.html
. There are some 3D game engines you can use to help you create 3D games with AS3.0 and Flash: Alternativa, Flare3D, Away 3D, and Adobe's own Proscenium. You can also use Stage 3D to make 2D games with full access to the computer or mobile devices Graphics Processing Unit (GPU) for great performance. The easy-to-use Starling framework can help you do this, as well as ND2D.