Here is the class declaration, variable declarations, plus the AnimatedObjectfunction.You can see the four parameters, defined very simply as x, y, dx, dy: package { import flash.display
Trang 2So, far, we have only built games where the game pieces stay in one place Theychange and accept player input, but they don’t move.
In this chapter, we work with animated game pieces Some will be controlled by theplayer, and others will have a life of their own
After looking at some animation examples, we’ll build two games The first is Air Raid,
a simple game in which you control an anti-aircraft gun and try to shoot down planesflying overhead The second game is Paddle Ball, in which you control a paddle anddirect a ball up into a field of blocks that disappear when the ball hits them
anima-Time-Based Animation
The basic idea of time-based animation is to move objects at a consistent rate, no ter how good or bad the performance of the Flash player
mat-A single movement, which we will call a step, takes place every frame So, a frame rate
of 12 frames per second should mean 12 steps per frame Even though the animationsteps occur in every frame, this will not be frame-based animation because we willdetermine the size of each step based on the time
For each step, we’ll calculate the time since the last step was taken Then, we will movethe game pieces according to this time difference
So, if the first step takes 84 milliseconds, and the second step takes 90 milliseconds,we’ll be moving things slightly farther in the second step than in the first step
Figure 5.1 shows a diagram of what three frames of movement using time-based tion might look like
Trang 3anima-The object in Figure 5.1 is supposed to move 400 pixels in 1 second anima-The movie is set
to a very slow four frames per second To complicate things, the computer is beingunresponsive, perhaps dealing with other applications or network activity It is unable todeliver an even frame rate, or even to generate four frames per second
When the first frame passes, and an ENTER_FRAME event triggers the animation function
on our code, 317 milliseconds have passed At 4 frames per second, only 250 onds should have passed So, the frame rate is already lagging
millisec-But by using the time of 317 milliseconds, we can calculate that the object should havemoved the distance of 127 pixels That’s 400 pixels per second, times 317 seconds
So, at the first frame, the object is exactly where it needs to be
The second frame takes even longer, an additional 423 milliseconds This is a total of
740 milliseconds, which places the object at 297 pixels out
Then, in the final frame of the example, an additional 260 milliseconds goes by Thisputs the time at exactly 1,000 milliseconds The distance is 400 So, after 1 second,the object has moved 400 pixels, despite the fact that the movie delivered an inconsis-tent frame rate and failed to generate 4 frames in the second
Trang 4If we had simply made the object move 100 pixels every frame, it would now be at
300 pixels out, having gotten only 3 frames to move This could be different on
another computer or at another time on the same computer, when performance wasgood enough to deliver 4 frames per second
Coding Time-Based Animation
The trick to coding time-based animation is to keep track of the time By looking at thefunctiongetTimer, you can get the number of milliseconds since the movie started Theactual value of getTimerisn’t important It is the difference in time between frames thatmatters
For instance, it may take 567 milliseconds for your movie to initialize and place items
on the screen So, the first frame happens at 567 and the second frame at 629 Thedifference is 62 milliseconds, which is what we need to know to determine how far anobject has moved between the frames
The movie AnimationTest.fla contains a simple circle movie clip to demonstrate based animation The movie uses AnimationTest.as as its main script and
time-AnimatedObject.as as the class for the movie clip.
TheAnimatedObjectclass has an constructor function that accepts parameters
This means that when you create a new AnimatedObject, you must pass parameters in,like this:
var myAnimatedObject:AnimatedObject = new AnimatedObject(100,150,5,-8);
The four parameters represent the horizontal and vertical location of the movie clip,plus the horizontal and vertical speed of the movie clip
Here is the class declaration, variable declarations, plus the AnimatedObjectfunction.You can see the four parameters, defined very simply as x, y, dx, dy:
package {
import flash.display.*;
import flash.events.*;
import flash.utils.getTimer;
public class AnimatedObject extends MovieClip {
private var speedX, speedY:Number; // current speed, pixels per second private var lastTime:int; // remember the last frame’s time
public function AnimatedObject(x,y,dx,dy) {
// set location and speed this.x = x;
this.y = y;
speedX = dx;
speedY = dy;
lastTime = getTimer();
Trang 5// move each frame
The function takes the four parameters and applies them The first two are used to setthe location of the movie clip The other two are stored in speedXandspeedY
Then, the variable lastTimeis initialized with the current value of getTimer() Finally,
addEventListenerwill allow the function moveObjectto run every frame
ThemoveObjectfunction first calculates the time passed, and then adds that to the
lastTime The value of timePassedis then used in calculating the change in location
NOTE
By adding timePassed to lastTime , you ensure that no time is lost in the animation If you instead set lastTime to getTimer() with every animation step, you might lose small slices of time between the calculation of timePassed and the setting of lastTime
Because timePassedis in thousandths of a second (milliseconds), we divide by 1,000 toget the correct amount to multiply by speedX andspeedY For instance, if timePassed is
100, that is the same as 100/1000 or 1 seconds If speedX is 23, the object moves23*.1 or 2.3 pixels to the right:
// move according to speed
public function moveObject(event:Event) {
// get time passed
var timePassed:int = getTimer() - lastTime;
Trang 6public class AnimationTest extends MovieClip {
public function AnimationTest() {
var a:AnimatedObject = new AnimatedObject(100,150,5,-8);
horizon-A better test of the AnimatedObjectclass is to add multiple objects and have them allmove around in random directions Here is a version of the main movie class that doesjust that:
package {
import flash.display.*;
public class AnimationTest extends MovieClip {
public function AnimationTest() {
// create 50 objects at random locations with random speeds for(var i:uint=0;i<50;i++) {
var a:AnimatedObject =
new AnimatedObject(Math.random()*550, dom()*400, getRandomSpeed(), getRandomSpeed()); addChild(a);
Math.ran-} }
// get a speed from 70-100, positive or negative
public function getRandomSpeed() {
var speed:Number = Math.random()*70+30;
In this version of the class, we create a new AnimatedObjectwith a random location and
a random speed The random location is made by the simple use of Math.random For arandom speed, however, I used a separate function that returns a value between 70 and
100, positive or negative This is to prevent having objects that are moving close to 0speed in a direction
Figure 5.2 shows this movie when it first runs The objects are scattered on the screen
Trang 7You can play with this class a bit to create some interesting effects For instance, if youhave all the objects starting at the same location, you get an explosion effect.
You can also adjust both the number of objects created and the frame rate of the movie
to see how well your computer handles a heavy load of animation
Now let’s use this technique in a game that has three different types of animatedobjects
NOTE
Naval torpedo games were probably easier to make in the early days of computer games because ships and torpedoes moved slowly compared to planes and anti-aircraft fire.
Trang 8In our game, the player moves an anti-aircraft gun along the bottom of the screen withthe keyboard arrows The player fires straight up at passing planes and tries to hit asmany as possible with a limited amount of ammo.
Movie Setup and Approach
This game is a perfect opportunity to create a game that uses multiple classes We’vegot essentially three different types of objects: airplanes, the turret, and bullets By cre-ating a single class for each, we can build the game step by step, and then specializethe code for each
We need three movie clips to go with the three classes The AAGunandBulletmovieclips will be one frame each However, the Airplanemovie clip will be several frames,each with a different drawing of a plane Figure 5.3 shows this movie clip The sixthframe through the end contains an explosion graphic that we will use when a plane
is hit
Figure 5.3
TheAirplanemovie
clip has five
differ-ent airplanes, each
in its own frame.
In addition to the three class files AAGun.as, Airplane.as, and Bullet.as, we need a main class file for the movie, AirRaid.as.
Flying Airplanes
The ActionScript class for the airplanes won’t be too different in structure from the
AnimatedObjectfrom earlier in this chapter It will accept some parameters in the structor function to determine the starting position and speed of the plane It will use thetime to track the difference between frames It will use an ENTER_FRAMEevent to step for-ward the animation
con-Class Declaration and Variables
The following code is the class definition and the variables the class will use Because theplane will only fly horizontally, it will only need dx, the horizontal speed:
Trang 9package {
import flash.display.*;
import flash.events.*;
import flash.utils.getTimer;
public class Airplane extends MovieClip {
private var dx:Number; // speed and direction
private var lastTime:int; // animation time
The Constructor Function
The constructor function will take three parameters: side,speed, and altitude The
sideparameter will be either “left”or“right”depending on which side of the screenthe plane will emerge from
Thespeedparameter will be used to fill the dxvariable If the plane is coming from theright side of the screen, we’ll automatically put a negative sign in front of the speed So,
a left-to-right plane with a speedof 80 will have a dxof 80 But, a right-to-left planewith a speed of 80 will have a dxof -80
Thealtitudeis just a fancy name for the vertical position of the plane So, 0 will bethe top of the screen, 50 will be 50 pixels below the top, and so on
In addition to setting the location and dx, we also need to flip the plane so that it facesthe right direction We can do this by using the scaleXproperty of the movie clip Avalue of –1 will flip the image:
public function Airplane(side:String, speed:Number, altitude:Number) {
if (side == “left”) {
this.x = -50; // start to the left
dx = speed; // fly left to right
this.scaleX = -1; // reverse
} else if (side == “right”) {
this.x = 600; // start to the right
dx = -speed; // fly right to left
this.scaleX = 1; // not reverse
The Airplanefunction ends by setting the event timer and initializing the lastTime
property just like we did in the AnimatedObjectclass
Trang 10Moving the Plane
ThemovePlanefunction first calculates the time passed, and then moves the planeaccording to the timer passed and the speed of the plane
Then, it checks to see whether the plane has completed its journey across the screen If
so, the deletePlanefunction is called:
public function movePlane(event:Event) {
// get time passed
var timePassed:int = getTimer()-lastTime;
NOTE
It is always a good idea to include a function with a class that deletes the object This way, the class can handle the removal of its own listeners and any commands needed
to clean up other references to itself.
For the plane to completely go away, we need to tell the main class that the plane isdone So, we start here by calling removePlane, a function of the main timeline’s class.The main timeline is what created the plane in the first place, and in doing so will store
it in an array The removePlane function, which we will get to in a minute, will removethe plane from the array:
// delete plane from stage and plane list
public function deletePlane() {
MovieClip(parent).removePlane(this);
parent.removeChild(this);
removeEventListener(Event.ENTER_FRAME,movePlane);
}
Trang 11After all references to an object have been reset or deleted, the Flash player will
reclaim the memory used by the object.
There will be a second function for removing the airplane This one looks similar to
deletePlane, but it will handle the situation where the plane is hit by the player’s fire Itwill also kill the frame event, and tell the main class to return the plane from the array.Instead of removing the child from the stage, however, it will just tell the movie clip to
go to the frame labeled “explode” and play from there
The movie clip has an explosion graphic starting at frame 6 This goes on for a fewframes, and then hits a frame with a simple parent.removeChild(this);and a stop();
on it This completes the deletion of the plane, after a brief glimpse at an explosion forthe player to enjoy:
// plane hit, show explosion
public function planeHit() {
You can make the explosion longer by lengthening the number of frames between the
“explosion” frame and the last one with the script on it Similarly, you can place an animated explosion on those frames with no additional ActionScript needed.
Testing the Airplane Class
The main timeline is what is in charge of creating the planes, and also removing them.We’ll create that class later If we want to test the Airplaneclass, we can do it with asimple main class like this:
package {
import flash.display.*;
public class AirRaid extends MovieClip {
public function AirRaid() {
var a:Airplane = new Airplane(“right”,170,30);
addChild(a);
}
}
}
Trang 12It is a good idea, if you are testing, to try different values for the parameters Forinstance, try a “left”and a speed of 30 Try as many different values as you need to
be sure that Airplaneis working before moving on to the next class
Moving Gun
The class that controls the anti-aircraft gun, seen in Figure 5.4, is a little different inthat the movement is controlled by user actions We could use the mouse to set theposition of the gun, but that would make the game almost too easy It only takes oneflick of the wrist to move from one side of the screen to the other
Figure 5.4
The anti-aircraft
turret is positioned
so its registration
point is at the tips
of the gun barrels.
So, instead, we’ll use the left and right arrow keys to move the gun Like the planes, itwill move at a set speed to the left or right, depending on which key is pressed
The arrow keys will actually be handled by the main movie class, not the AAGunclass.This is because the keyboard, by default, sends events to the stage, not a particularmovie clip
The main movie class will have two variables, leftArrowandrightArrowthat will be set
totrueorfalse The AAGunclass simply looks to those variables to see what direction, ifany, to send the gun:
package {
import flash.display.*;
import flash.events.*;
import flash.utils.getTimer;
public class AAGun extends MovieClip {
static const speed:Number = 150.0;
private var lastTime:int; // animation time
public function AAGun() {
// initial location of gun
Trang 13func-public function moveGun(event:Event) {
// get time difference
var timePassed:int = getTimer()-lastTime;
lastTime += timePassed;
// current position
var newx = this.x;
// move to the left
It is worth looking at how the main class handles the key presses right now In the structor function, two addEventListenercalls set it up:
con-stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);
Trang 14The two functions that are called set the Boolean values of leftArrowandrightArrow
The event.keyCode value is a number that is matched to a key on the keyboard Key
37 is the left arrow, and key 39 is the right arrow Key 38 and 40 are the up and down arrows, which we will use in other chapters.
So, the movement of the gun is really a joint effort by the main class and the AAGun
class The main class handles the keyboard input, and the AAGunclass handles the ment
move-There is one more part to AAGun, the deleteGunfunction We’ll only be using this when
it is time to remove the gun from the stage to jump to the gameover frame:
// remove from screen and remove events
public function deleteGun() {
Trang 15Skyward Bullets
Bullets are probably the simplest of all the moving objects In this game, the graphic isactually a grouping of bullets as seen in Figure 5.5
Figure 5.5
The bullet grouping
has the registration
point at the
bot-tom, so when they
start at the gun,
they are just above
the tops of the
barrels.
They will originate at the location of the gun, and move directly upward until they reachthe top of the screen All the code in the Bullet class we have seen before in the
AirplaneandAAGunclasses
The constructor function will accept a starting xandyvalue, and a speed The speedwill be applied vertically, rather than horizontally like the airplanes:
package {
import flash.display.*;
import flash.events.*;
import flash.utils.getTimer;
public class Bullet extends MovieClip {
private var dy:Number; // vertical speed
private var lastTime:int;
public function Bullet(x,y:Number, speed: Number) {
// set start position
public function moveBullet(event:Event) {
// get time passed
Trang 16var timePassed:int = getTimer()-lastTime;
lastTime += timePassed;
// move bullet this.y += dy*timePassed/1000;
// bullet past top of screen
if (this.y < 0) { deleteBullet();
} }
TheremoveBulletfunction, like the removePlanefunction, will exist in the main class Itwill be in charge of removing bullets when they reach the top of the screen:
// delete bullet from stage and plane list
public function deleteBullet() {
To start a bullet, the player presses the spacebar We need to modify the
keyDownFunction in the AirRaidclass to accept spaces and pass them along to a tion that handles the creation of a new Bullet:
ThefireBulletfunction passes the location of the gun and a speed to the new Bullet
It will also add the new Bulletto the array bulletsso that it can keep track of it laterfor collision detection:
Trang 17public function fireBullet() {
var b:Bullet = new Bullet(aagun.x,aagun.y,-300);
addChild(b);
bullets.push(b);
}
Now that we have airplanes, an anti-aircraft gun, and Bulletobjects, it is time to tie all
of these together with the main AirRaidclass
The Game Class
The AirRaidclass contains all the game logic It is here that we will create the initialgame objects, check for collisions, and handle scoring After the game gets going, it willlook something like Figure 5.6
Figure 5.6
The Air Raid game
with anti-aircraft
gun, bullet in
mid-movement, and two
airplanes flying
overhead.
Class Declaration
The class needs the standard classes we have been using so far, including access to
getTimerand text fields:
refer-public class AirRaid extends MovieClip {
private var aagun:AAGun;
private var airplanes:Array;
private var bullets:Array;
Trang 18The next two variables are trueorfalsevalues that track the player’s use of the and right-arrow keys These need to be publicvariables because the aagunobject will
left-be accessing them to determine whether to move:
public var leftArrow, rightArrow:Boolean;
NOTE
You can include more than one variable on a variable definition line This works great when you’ve got small groups of variables that are related and of the same type The
leftArrow and rightArrow variables are a good example.
The next variable, nextPlane, is going to be a Timer We’ll use this to determine whenthe next plane will appear
private var nextPlane:Timer;
Finally, we’ve got two score-keeping variables The first keeps track of how many shotsare left, and the second how many hits the player scored:
private var shotsLeft:int;
private var shotsHit:int;
There is no AirRaidconstructor function for this game because it is not starting on thefirst frame Instead, we’ll have one called startAirRaidthat will be called from the maintimeline on the “play” frame
The function starts off by setting the number of shots left to 20 and the score to 0:
public function startAirRaid() {
We also need to start off the arrays to hold the bullets and airplanes:
// create object arrays
airplanes = new Array();
bullets = new Array();
To know which arrow keys have been pressed, we need two listeners, one for the keydown events, one for the key up events:
// listen for keyboard
stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownFunction);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpFunction);
Trang 19We need an ENTER_FRAMEevent listener to trigger the checkForHitsfunction This will bethe all-important collision detection between the bullets and the planes:
// look for collisions
addEventListener(Event.ENTER_FRAME,checkForHits);
Now, we need to kick off the game by getting some planes in the air The setNextPlane
function will do this, and we look at it next:
// start planes flying
setNextPlane();
}
Creating a New Plane
New planes will need to be created periodically, at somewhat random times To do this,we’ll use a Timerand trigger a newPlanefunction call in the near future The
setNextPlanefunction will create the Timerwith only one event, and set it for one totwo seconds in the future:
public function setNextPlane() {
nextPlane = new Timer(1000+Math.random()*1000,1);
Finally, the setNextPlanefunction is called again to schedule the next plane:
public function newPlane(event:TimerEvent) {
// random side, speed and altitude
var altitude:Number = Math.random()*50+20;
var speed:Number = Math.random()*150+150;
Trang 20Collision Detection
The most interesting function in this entire game is the checkForHitsfunction It looks
at all the bullets and all the airplanes and determine whether any of them are ing at the moment
intersect-NOTE
Notice that we are looping backward through the arrays This is so that when we delete an item from an array we don’t trip over ourselves If we were moving forward through the array, we could delete item 3 in the array, which would make the old item
4, the new item 3 Then, moving forward to look at item 4, we would be skipping an item.
We’ll use the hitTestObjectto see whether the bounding boxes of the two movie clipsoverlap If they do, we’ll do several things First, we’ll call planeHit, which will start thedeath of the airplane Then, we’ll delete the bullet We’ll up the number of hits andredisplay the game score Then, we’ll stop looking at collisions for this airplane andmove on to the next bullet in the list:
// check for collisions
public function checkForHits(event:Event) {
for(var bulletNum:int=bullets.length-1;bulletNum>=0;bulletNum ){
for (var airplaneNum:int=airplanes.length-1;airplaneNum>=0;airplaneNum ) {
if (bullets[bulletNum].hitTestObject(airplanes[airplaneNum])) { airplanes[airplaneNum].planeHit();