Read Foundation Game Design with ActionScript 3.0, Second Edition Online
Authors: Rex van der Spuy
There are two details I need to point out. First, theCharacter
class is extending theSprite
class.
public class Character
extends
Sprite
This means that any game objects you make using theCharacter
class are actuallySprite
objects under their skin. Theextends
keyword means that theCharacter
class has
inherited
all the properties and methods of theSprite
class. It means that you can use all the same properties and methods that you usually use withSprite
objects. Properties like x, y, visible, alpha, or methods likeaddChild
will all work with any objects that you make with this newCharacter
class.
This is an important programming concept called
inheritance
. When you use theextends
keyword, the new class you're making “inherits” all of the properties and methods of the class you're extending. Inheritance is a key feature of a programming style called Object Orient Programming (OOP). AS3.0 is an OOP language, as is Java, C++, C #, and Objective C.
It also means that you don't have to create a separateSprite
object and add the image to it. The image is already wrapped inside aSprite
because theCharacter
extends theSprite
class.
All of this means thatCharacter
objects will be able do everything thatSprite
objects can, with the bonus that they display the image of the game character.
But where is the character.png actually being displayed? It's not being displayed on the stage. It's being displayed inside
this
class. That's what this line does:
this.
addChild(gameObjectImage);
The keywordthis
means “this class.” This line of code means that you're adding thegameObjectImage
to
this
,Character
, class. The result is that whenever you use aCharacter
class object in a game, the character.png image will automatically be displayed. It's part of the class.
Why didn't you usestage.addChild()
like you've done in other programs? That's because only the application class can add things directly to the stage. The application class, in this case, isTimeBombPanic.as
. You'll see how it will add aCharacter
class object to the stage very soon.
So now you know that theCharacter
class just has the job of displaying the character.png image. But what do theBomb
,Box
,Background
, andGameOver
classes do? Exactly the same thing: they display the images you designed in the first part of the chapter. In fact, the code in each is almost identical. Take a look at theBox
class.
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
public class
Box
extends Sprite
{
//Embed the image
[Embed(source="../images/box.png")]
public var GameObjectImage:Class;
public var gameObjectImage:DisplayObject
= new GameObjectImage();
public function
Box
()
{
this.addChild(gameObjectImage);
}
}
}
The only difference between theBox
class and theCharacter
class is the name and the PNG file that it's embedding. Browse through the other classes and you'll see that they all follow this identical format.
So now that you've got these classes and stuffed your game graphics inside them, how do you use them? You first have to make objects from them, and you can do this in the application class.
Of course you already know how to make objects: with thenew
keyword. You can make an object from theCharacter
class like this:
public var character:Character = new Character();
You can then add it to the stage like this:
stage.addChild(character);
You can now use thecharacter
object anywhere you like in your game, and it will work like any otherSprite
object you've ever created. But the one bonus is that it will already contain the character.png image.
Where this saves you a lot of work is if you have to make multiple copies of an object. There are 14 boxes in Time Bomb Panic. You don't need to make 14 separate classes for each box. You just need one parentBox
class and you can make 14 instances (copies) of it. Each of those instances will automatically contain the embedded box.png image. This saves you having to type out dozens of lines of repetitive code.
Here's how you can make multiple box instances using just oneBox
class. First, make a fewbox
objects in the application class.
public var box1:Box = new Box();
public var box2:Box = new Box();
public var box3:Box = new Box();
You can add them to the stage like this:
stage.addChild(box1);
stage.addChild(box2);
stage.addChild(box3);
There's not a single Embed metatag in sight!box1
,box2
, andbox3
will all contain the box.png image that was embedded into their parentBox
class.
Do you see now how classes are just “things” in your game?
These five simple classes have just contained images, but you can put anything you like into a class. In the next chapter, you'll see how to put logic code inside them so that you can create objects with very complex, autonomous behavior.
Figure 7-76
illustrates how these object classes work with the application class to produce the images that you can see on the stage.
Figure 7-76
. The application class makes game objects from the game object classes.
Now that you know your five game objects are self-contained classes, let's take a look at the entireTimeBombPanic
application class, and I'll show you how they've been used in the game.
I'm going to list the entireTimeBombPanic
application here so that you have a reference to it for the rest of the chapter. You'll recognize some very familiar code, but a few new things as well. I'll walk you through exactly how all of it works.
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.text.*;
import flash.ui.Keyboard;
import flash.events.TimerEvent;
import flash.utils.Timer;
[SWF(width="550", height="400",
backgroundColor="#FFFFFF", frameRate="60")]
public class TimeBombPanic extends Sprite
{
//Create the text objects
public var format:TextFormat = new TextFormat();
public var output:TextField = new TextField();
public var input:TextField = new TextField();
public var gameResult:TextField = new TextField();
//Create the game objects
public var character:Character = new Character();
public var background:Background = new Background();
public var gameOver:GameOver = new GameOver();
//The bombs
public var bomb1:Bomb = new Bomb();
public var bomb2:Bomb = new Bomb();
public var bomb3:Bomb = new Bomb();
public var bomb4:Bomb = new Bomb();
public var bomb5:Bomb = new Bomb();
//The boxes
public var box1:Box = new Box();
public var box2:Box = new Box();
public var box3:Box = new Box();
public var box4:Box = new Box();
public var box5:Box = new Box();
public var box6:Box = new Box();
public var box7:Box = new Box();
public var box8:Box = new Box();
public var box9:Box = new Box();
public var box10:Box = new Box();
public var box11:Box = new Box();
public var box12:Box = new Box();
public var box13:Box = new Box();
public var box14:Box = new Box();
//Create the timer
public var timer:Timer;
//Create and initialize the vx and vy variables
public var vx:int = 0;
public var vy:int = 0;
//The bombsDefused variable that counts
//the number of bombs collected
public var bombsDefused:uint = 0;
public function TimeBombPanic()
{
createGameObjects();
setupTextfields()
setupEventListeners();
}
public function createGameObjects():void
{
//Add the background
addGameObjectToStage(background, 0, 0);
//Add the character
addGameObjectToStage(character, 50, 50);
//Add the boxes
addGameObjectToStage(box1, 100, 100);
addGameObjectToStage(box2, 150, 100);
addGameObjectToStage(box3, 200, 100);
addGameObjectToStage(box4, 150, 150);
addGameObjectToStage(box5, 100, 250);
addGameObjectToStage(box6, 200, 250);
addGameObjectToStage(box7, 250, 250);
addGameObjectToStage(box8, 250, 200);
addGameObjectToStage(box9, 300, 100);
addGameObjectToStage(box10, 300, 300);
addGameObjectToStage(box11, 350, 250);
addGameObjectToStage(box12, 400, 100);
addGameObjectToStage(box13, 400, 200);
addGameObjectToStage(box14, 400, 250);
//The bombs
addGameObjectToStage(bomb1, 105, 160);
addGameObjectToStage(bomb2, 205, 310);
addGameObjectToStage(bomb3, 305, 260);
addGameObjectToStage(bomb4, 355, 310);
addGameObjectToStage(bomb5, 455, 110);
//Add the gameOver image and
//make it invisible when the game starts
addGameObjectToStage(gameOver, 125, 50);
gameOver.visible = false;
//Initialize the timer
timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, updateTimeHandler);
timer.start();
}
public function setupTextfields():void
{
//Set the text format object
format.font = "Helvetica";
format.size = 38;
format.color = 0xFFFFFF;
format.align = TextFormatAlign.CENTER;
//Configure the output text field
output.defaultTextFormat = format;
output.autoSize = TextFieldAutoSize.CENTER;
output.border = false;
output.text = "0";
//Display and position the output text field
stage.addChild(output);
output.x = 265;
output.y = 7;
//Configure and display the gameResult Textfield
format.color = 0x000000;
format.size = 32;
gameResult.defaultTextFormat = format;
gameResult.autoSize = TextFieldAutoSize.CENTER;
gameResult.text = "You Won!";
gameOver.addChild(gameResult);
gameResult.x = 145;
gameResult.y = 160;
}
public function setupEventListeners():void
{
stage.addEventListener
(KeyboardEvent.KEY_DOWN, keyDownHandler);
stage.addEventListener
(KeyboardEvent.KEY_UP, keyUpHandler);
stage.addEventListener
(Event.ENTER_FRAME, enterFrameHandler);
}
public function updateTimeHandler(event:TimerEvent):void
{
output.text = String(timer.currentCount);
//Stop the timer when it reaches 10
if(timer.currentCount == 10)
{
checkGameOver();
}
}
public function enterFrameHandler(event:Event):void
{
//Move the player
character.x += vx;
character.y += vy;
//Stage boundaries
if (character.x < 50)
{
character.x = 50;
}
if (character.y < 50)
{
character.y = 50;
}
if (character.x + character.width > stage.stageWidth - 50)
{
character.x = stage.stageWidth - character.width - 50;
}
if (character.y + character.height > stage.stageHeight -50)
{
character.y = stage.stageHeight - character.height - 50;
}
//Box Collision code
Collision.block(character, box1);
Collision.block(character, box2);
Collision.block(character, box3);
Collision.block(character, box4);
Collision.block(character, box5);
Collision.block(character, box6);
Collision.block(character, box7);
Collision.block(character, box8);
Collision.block(character, box9);
Collision.block(character, box10);
Collision.block(character, box11);
Collision.block(character, box12);
Collision.block(character, box13);
Collision.block(character, box14);
//Bomb collision code
if(character.hitTestObject(bomb1) && bomb1.visible == true)
{
bomb1.visible = false;
bombsDefused++;
checkGameOver();
}
if(character.hitTestObject(bomb2) && bomb2.visible == true)
{
bomb2.visible = false;
bombsDefused++;
checkGameOver();
}
if(character.hitTestObject(bomb3) && bomb3.visible == true)
{
bomb3.visible = false;
bombsDefused++;
checkGameOver();
}
if(character.hitTestObject(bomb4) && bomb4.visible == true)
{
bomb4.visible = false;
bombsDefused++;
checkGameOver();
}
if(character.hitTestObject(bomb5) && bomb5.visible == true)
{
bomb5.visible = false;
bombsDefused++;
checkGameOver();
}
}
public function checkGameOver():void
{
if(bombsDefused == 5)
{
gameOver.visible = true;
gameResult.text = "You Won!";
character.alpha = 0.5;
background.alpha = 0.5;
timer.removeEventListener
(TimerEvent.TIMER, updateTimeHandler);
stage.removeEventListener
(Event.ENTER_FRAME, enterFrameHandler);
}
else if(timer.currentCount == 10)
{
gameOver.visible = true;
gameResult.text = "You Lost!";
character.alpha = 0.5;
background.alpha = 0.5;
timer.removeEventListener
(TimerEvent.TIMER, updateTimeHandler);
stage.removeEventListener
(Event.ENTER_FRAME, enterFrameHandler);
}
}
public function addGameObjectToStage
(gameObject:Sprite, xPos:int, yPos:int):void
{
stage.addChild(gameObject);
gameObject.x = xPos;
gameObject.y = yPos;
}
public function keyDownHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT)
{
vx = -5;
}
else if (event.keyCode == Keyboard.RIGHT)
{
vx = 5;
}
else if (event.keyCode == Keyboard.UP)
{
vy = -5;
}
else if (event.keyCode == Keyboard.DOWN)
{
vy = 5;
}
}
public function keyUpHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT
|| event.keyCode == Keyboard.RIGHT)
{
vx = 0;
}
else if (event.keyCode == Keyboard.DOWN
|| event.keyCode == Keyboard.UP)
{
vy = 0;
}
}
}
}