Creating Critter Attack


Creating Critter Attack

For this chapter's game, we're going to produce a generic Space Invaders style game. There is an entire genre of shooting games that evolved from that original game, so it's probably a good idea to take a look at how we might construct such a game in Flash. We'll be making use of initialization objects, color transforms, and depth organizing clips in our version of this game, named Critter Attack .

As usual, there are two .fla files on the CD, one containing the game in an unfinished state where all the art assets are in place but the script is missing, and the other containing the finished game. There is also an Art Asset folder containing the raw art Rachel sent me.

The Idea

Space Invaders was a pretty simple game, and ours will be simple, too. There are only a few game objects we need to worry about:

  • The player's spaceship

  • The aliens

  • The laser beams

  • The Game Over panel

  • The scoreboard

The player controls his spaceship with the arrow keys, which move him horizontally on the screen. The aliens move as one large block back and forth across the screen. Each time the aliens get to the edge, they creep down a bit, drawing closer to the player.

The spaceship can fire lasers at the aliens using the spacebar, and the aliens can fire lasers back. When the player shoots an alien, it dies and disappears. When the aliens shoot the player, his ship becomes slightly redder in color. When the player's ship has been shot several times and becomes completely red, the player dies and his game ends. If the aliens get all the way to the bottom of the screen, the player dies.

When the player is dead, a Game Over panel opens up displaying his score and containing a Reset button to allow him to start over.

If the player kills all the aliens on the screen, the aliens are respawned and things move more quickly. A scoreboard keeps track of both the player's score and how many times he has killed all the aliens (his level).

Everything has been exported for ActionScript using an export name that is identical to each symbol name .

The final preparations include setting the frame rate to 30 for smoothest visual appearance, changing the background to black, and making the movie 600 — 500 pixels.

The Implementation

This game is a bit more complex than what we've done so far. It's going to take a bit more organization to keep everything straight. To deal with this, I use a lot of functions. That way, things can be broken down into reusable parts and I can easily find the piece I need to work with.

We're going to be encapsulating a lot of the functionally in this program. That means that the ship movie clip will have its own onEnterFrame handler that does the work necessary to handle the ship each frame. The aliens will have their own onEnterFrame handler that will deal with the business of moving the aliens and making them shoot at the player. This modularity not only makes things easier to change later, but it also makes it more intuitive to develop in the first place.

Before we initialize the game, we need to talk a bit about how the game will be laid out. Both our ship and the aliens will be able to move left and right based on how wide our movie is. It's convenient to use the Stage object to get the height and width of the stage to calculate the center of the field as well as the boundaries. To do that though, we need to set up our movie in a way that our game will work no matter what the stage size happens to be. We wouldn't want the game to break just because we changed the size listing in the HTML.

To keep the game working at all times, especially when we are trying to test our game in Flash with a maximized test area, we need to set the alignment for the movie to go to the upper-left corner. That means that the (0,0) of the main timeline will always be in the upper-left corner. This is useful in the same way that it is good for us to keep our attached movie clips at the (0,0) of their timelines so that no extra math has to be done to figure out where everything is.

In addition to setting the alignment, let's also set the scaleMode of the .swf to be "noScale". This will mean that we can change the dimensions in the HTML, and the game will change its overall area and make the game bigger or smaller. That way, the game can always be the perfect size. To do these two tasks , place the following two lines of code at the top of frame 1 of the main timeline.

 Stage.align=" TL" Stage.scaleMode=" noScale" 

Now we can turn our attention to setting up the actual game. In any game, there is a block of code that needs to be run only once ”when the game first begins. In this case, I've named that function initGame . That leads me to the following script:

Note  

Just as a reminder, you can call a function before it is defined as long as the function is defined in the same frame.

 initGame(); function initGame(){ } 

We have a single call to initGame to set up everything we need. This function is never called again in the life of our program. After the call, we give the implementation of initGame , which is currently empty. We'll fill this in as we go, bit by bit.

In the previous section, we bulleted each game object. That list included the ship, aliens, bullets, scoreboard, and Game Over panel. We can implement each of these separately. However, first there are a few things we need to look at involving the overall design.

The aliens, alien bullets, and player bullets will be organized using container clips. That means we're going to create one empty clip called aliens , and inside it we'll attach all the individual aliens. This serves several purposes: First, we can move all the aliens by moving the container clip, and second, the container clip helps us organize our depths. By setting the alien container's depth relative to the other stage elements, we can place the entire set of aliens at the proper depth. When we create the individual aliens, they are children of their container clip and as such, they have a depth setting that is relative to that container. That means that the individual alien depths cannot conflict with anything else, including the player's ship, bullets, scoreboard, and so on. This will be clear when we actually get to the code.

Before we start implementing the pieces, I want to set the depths for everything we'll need. That way, all depths are set at the same place in the script for easy modification later. The following addition to our initGame function should take care of all our depths:

 starDepth = 50;     scoreboardDepth = 75;     alienBulletsDepth = 98;     playerBulletDepth = 99;     shipDepth = 100;     alienDepth = 101;     gameoverDepth = 102; 

I order these by their relative depth settings to make things easily readable. You can see from the settings that the star depth is set lowest , followed by the scoreboard depth. After that, we have the alien and player bullet depths, the ship depth, the alien depth, and finally, the Game Over panel depth.

We want to assign another set of variables in the initGame function. They control the speed at which the player's ship moves, the speed that the aliens move, the speed that the bullets move, and other similar values. All these variables are assigned inside the initGame function, just after the depth settings:

 originalAlienSpeed = alienSpeed = 1;     originalFireDelay = fireDelay = 16; laser     originalAlienFireDelay = alienFireDelay = 15;     originalPlayerBulletSpeed = playerBulletSpeed = 20;     originalAlienBulletSpeed = alienBulletSpeed = 10;     rowOffset = 50; //used to space out aliens at creation     colOffset = 65; //used to space out aliens at creation     redStep = 20; 

We are using two of each because these values will change when the player kills all the aliens. When the player dies, we'll want to reset them to their original values, so we store those originals and change only the copies.

One variable to point out here is the redStep variable. To demonstrate the color object, we are going to make the ship turn more and more red as it takes damage. The redStep variable indicates how much to add to the red b value for a color transformation.

The Scoreboard

This piece is easy enough. We have a clip in the library that has a score and a level text field. The score text field has its variable set to _root.score , and the level text field has its variable set to _root.level . Therefore, the creation and implementation of our scoreboard can be given with the following script:

 function createScoreboard(){      attachMovie("scoreboard"," scoreboard",scoreboardDepth, {_y:Stage.height});      score = 0;      level = 1; } 

Notice that our attachment call uses scoreboardDepth to set the depth. That is the way I do all my depths ”using the clip name with the Depth extension. This depth and the rest of the clip depths are defined in the initGame function.

Now we need to make a call to this function inside our initialization function, as follows :

 function initGame(){  ...depth and balance constants...    createScoreboard();   } 
Caution  

The line ... depth and balance constants ... is meant only to fill in for the list of depths given in the previous section. This is not intended as actual ActionScript.

The Ship

This one is going to take some work. First we need some constants to control the speed at which the ship moves. This script goes inside the initGame function defined earlier:

 originalSpeed = speed = 12; 

We use two variables ” speed and originalSpeed ”because each time the player clears a level, we want to increase the speed of his ship. When the player finally dies and restarts the game at level 1, we want to be able to reset the speed to its original value.

Now we can add a function call to the end of our initGame script, as follows:

 createShip(); 

And, of course, that leaves us the task of implementing this function.

The createShip Function

What follows is the outline for the createShip function:

 function createShip(){ } 

The rest of the script in this section goes inside the createShip function we just started.

To create the ship, we need to do several things. First we need to attach a ship clip to the main timeline:

 attachMovie("ship"," ship",shipDepth,{_x:Stage.width/2,    _y:Stage.height-65,_xscale:18,_yscale:18}); 

Our ship is going to have a movie clip with a flame in it to indicate that the ship is in motion. When the ship isn't moving, the flame should dissapear. Because the ship will start at rest, we need to turn the flame invisible ourselves .

 ship.flame._visible=false; 

Now it's time to attach the handlers for the ship. We need a keyUp , keyDown , and enterFrame handler:

 ship.onKeyUp=shipKeyUp; ship.onKeyDown=shipKeyDown; ship.onEnterFrame=shipEnterFrame; 

Now we need to attach a script that handles the firing of bullets from the ship:

 ship.fire = firePlayerBullet; 

To get the keyUp and keyDown handlers to work, we must register the ship clip as a listener for the Key object:

 Key.addListener(ship); 

When the player gets hit, his ship turns slightly more red. To do this, we need two things. First, we need a Color object that is tied to the ship clip, and second, we need a color transform object that we can use to steadily increase the amount of red in the player's ship each time it is hit:

 ship.myColor = new Color(ship); ship.myColorTransform = {rb:0, bb:0}; 

Notice how I attach each of these new objects to the ship clip? That's because both the Color object and the Color Transform object are to be used only with the ship. What more logical place to keep these objects than on the object they are intended to modify? Also, I initialized the myColorTransform object because we will be incrementing and decrementing these values. Flash MX 2004 now requires that these variables be initialized with a value for these sorts of operations to occur.

Finally, we need to create a container clip for the player's bullets:

 createEmptyMovieClip("playerBullets",playerBulletDepth); 

The only thing left to do with the ship is implement the event handler functions that we've already attached to the instance. Let's look first at the two keyboard handlers.

The shipKeyDown Function

This function was attached to the ship's onKeyDown handler. As such, it's responsible for monitoring the user 's keyboard events. Because the arrow keys will control the ship, this is the logical handler to use.

Using the Key object we learned about earlier in this chapter, we can use the following script to monitor the keyboard for user commands:

 function shipKeyDown(){      k=Key.getCode(); } 

This script gets the ship trapping keyDown events. Each time this happens, k is used to get the keycode of the last key pressed (the keystroke that caused this event in the first place).

From here, we can analyze the key to determine if it's one we need to handle. (The only keys necessary to handle are the left and right arrows and the spacebar.) The following script segments go inside the shipKeyDown function we outlined earlier:

 if(k==Key.LEFT) ship.left=true; 

If the user is pressing the left arrow, we set the left property of the ship to true . This property is used in the onEnterFrame handler for the ship to let us know the user is trying to move left:

 else if(k==Key.RIGHT) ship.right = true; 

This line traps the right arrow and sets another property of the ship object ”this time the ship.right property ”to true :

 else if(k==Key.SPACE){ship.firing=true; ship.fire();} 

We now trap the spacebar key event. If that's the key our user pressed, we set the ship.firing property to true and call the ship.fire function.

Now we need to deal with the ship's flame. If the user is pressing left or right, we want to turn the flame on. If the user is pressing both left and right, we want to turn the flame off. That's because when the user presses both arrow keys, we want our ship to stay put. This is a perfect use of the exclusive OR (XOR) operator ( ^ ). XOR returns true when one argument is true but the other is not. If both arguments are true or both are false , XOR should return false .

Let's test our ship.left and ship.right properties to see if we need the flame to be on or off:

 if(ship.left^ship.right)ship.flame._visible=true; else ship.flame._visible=false; 

That concludes the trapping of keydown events to handle moving the ship. We now need to watch for keyup events so that we can turn the left and right properties to false when the user releases the arrow keys.

The shipKeyUp Function

This function is similar to the previous one, except that it does the opposite : It watches for keyUp events. We begin in the same way: by defining our function and getting the last key to be released (the key that caused the event in the first place):

 function shipKeyUp(){      k=Key.getCode(); } 

Now we can add more script inside this function. First we need to see if the user released the left key:

 if(k==Key.LEFT) ship.left=false; 

As you can see, we set the ship.left property to false if the user has released the left arrow. Now we do the same with the right arrow:

 else if(k==Key.RIGHT) ship.right=false; 

At this point, we need to handle the release of the spacebar:

 else if(k==Key.SPACE) ship.firing=false; 

Finally, we need to see if our flame needs to be on or off:

 if(!ship.left && !ship.right) ship.flame._visible=false; else ship.flame._visible=true; 
The shipEnterFrame Function

Recall that this function was attached to the ship's onEnterFrame handler. As such, it's responsible for handling any ship behavior that needs to be updated every frame. That includes movement and firing. First we define our function as follows:

 function shipEnterFrame(){ } 

Now we can add pieces to it. First we deal with the ship's movement. The logic goes like this. If the user is pressing the left button and is not pressing the right button, and the user has not moved too far to the left already, move him left. This logic is implemented with the following script:

 if(ship.left && this._x>15+speed && ship.left^ship.right)       this._x-=speed; 

Now we need to test the opposite, going right with the right arrow:

 else if(ship.right && this._x<Stage.width-15-speed && ship.left^ship.right)      this._x+=speed; 

In these preceding two script pieces, we are using the XOR operator again to make sure the user is only pressing one of the two arrow keys. We're also making sure the user is not too far left ( 15+speed ) or too far right ( Stage.width-15-speed ). The value of 15 is to keep the graphic of the ship from going off the screen. We use speed so that we can make sure that where the ship will be moving won't be out of bounds.

The preceding script handles all our movement. All that's left is to handle the firing of the gun.

In the shipKeyDown function, when the user pressed the spacebar, we called the fire method and set the ship.fireDelay equal to a constant ( fireDelay ). That delay is the number of frames the player must wait after shooting to be able to shoot again. The following script implements that:

 if(ship.fireDelay > 0)      -ship.fireDelay; 

In other words, if the ship's fireDelay is greater than 0, we need to wait, so subtract 1 from the delay:

 else ship.fire = firePlayerBullet; 

If that is not the case and the delay is 0, we attach the firePlayerBullet function to the ship.fire method.

Finally, if the user is holding down the spacebar, ship.firing is true , in which case we need to call the fire method again:

 if(ship.firing) ship.fire(); 

And that completes the ship's enterFrame routine. In addition, it completes the entire ship implementation, excluding the ship's firing of bullets, which will come later. Go ahead and test things; you should see something similar to Figure 6.25.

click to expand
Figure 6.25: The ship is now controllable with the keyboard.

The Aliens

Now that the player's ship is out of the way, let's implement the aliens. The first thing we need to do is add the following line to our initGame function:

 createAliens(); 
The createAliens Function

Recall that we are going to use a container clip to keep all our aliens in. This helps us organize depth and move the aliens as a group . In addition to this container clip, we need to store an array of alien references so that we can easily choose one at random to fire a bullet at the player. These two requirements give rise to the following script:

 function createAliens(){       createEmptyMovieClip("aliens",alienDepth);       alienArray = new Array(); } 

Our container clip is named aliens and our array is named alienArray . These are crucial pieces of the puzzle for us, so take strong note of their names .

We also want to keep track of how many aliens are in the game at any time. The following script is added to the createAliens function given earlier:

 aliens.alienCount=0; 

Notice that my alien counter ( alienCount ) is attached as a property of the aliens container clip. That's just to keep everything organized. Now we need to go about the business of actually creating alien clips and distributing them about the stage. We're going to use the initialization object technique to save us some keystrokes and clean up the code:

 initObj = new Object(); initObj._xscale = 30; initObj._yscale = 30; 

That gets our initObject almost ready. Now we start our alien creation loop. We loop five times, once for each row of aliens:

 for(rows=0;rows<5;++rows){      switch(rows){            //pick which alien type goes in this row            case 0: alienNumber=2; break;            case 1: alienNumber=4; break;            case 2: alienNumber=1; break;            case 3: case 4: alienNumber=3; break;      } 
Note  

Remember that when you have a case that does not end with a break, the code for the next case will also run, as you can see with cases 3 and 4.

We've chosen an alien type for this row, which gives us the aliens sorted by row with their respective types. Now we're ready to go into an inner for loop that will iterate once for each column. We're using seven columns of aliens in this game, so that gives us the following script:

 for(cols=0;cols<7;++cols){              initObj.scoreStep = (6-rows) * 100;              initObj._x = cols*colOffset+colOffset/2;              initObj._y = rows*rowOffset+rowOffset/2;              alienArray.push(aliens.attachMovie("alien"+alienNumber,    " alien"+aliens.alienCount, aliens.alienCount++,initObj));              }        } 

That completes the previous for loop that iterated for each row. We should now have a mess of aliens on the stage, as well as an array of references to them. There is a lot going on in the previous script, so let's take a careful look at a few pieces.

The scoreStep property is going to be used when the player kills an alien. Some aliens have a higher value than the rest, and this alien property determines that.

The attachMovie line comes inside a call to alienArray.push . That's because attachMovie returns a reference to the recently created clip. By placing the attachMovie call inside the push call, we are able to attach a new alien clip and push a reference to it into our array, all in one line of code.

Now that we're finished with the initObject , we should get rid of it:

 delete initObj; 

We need to attach an onEnterFrame handler for the aliens:

 aliens.onEnterFrame = alienEnterFrame; 

One more property of aliens that needs to be created is called direction . This property is used so that the aliens can keep track of which way they are moving. When the game is running, the aliens move back and forth across the screen, moving down a bit each time they get to an edge. The current direction they are moving is important, so we'll need to record it with the following script:

 aliens.direction = 0; 
Note  

I set direction to be 0 because there are only four directions ”right, down, left, and down again ”and I have assigned them the numbers 0, 1, 2, and 3, respectively. This will make sense in the next section when we describe the onEnterFrame handler, which deals with aliens' movement.

Finally, we need to create a container clip for the alien bullets, just like we did with the player bullets:

 createEmptyMovieClip("alienBullets",alienBulletsDepth); 
The alienEnterFrame Function

Now we're ready to give the aliens the enterFrame handler. We named this function alienEnterFrame in the previous section when we attached it to the aliens onEnterFrame handler, but now we're ready to define it:

 function alienEnterFrame(){ } 

Inside this function, we first deal with the aliens firing a bullet. Remember that we're using a frame delay like we did with the player's ship. The property was defined to be aliens.fireDelay , so the following script would go inside the function we've started in the previous script:

 if(aliens.fireDelay > 0)           aliens.fireDelay;      else fireAlienBullet(); 

As you can see, this is almost identical to the player's firing code except that it calls fireAlienBullet instead of ship.fire .

Now it's time to deal with the movement of the aliens. Because we have grouped all the aliens into the same clip, we can use the bounds of that clip to determine how far to move each direction. We'll use the MovieClip.getBounds method to accomplish this:

 var b = new Object();     b = aliens.getBounds(_root); 

At this point, we have an object, b , that contains the bounds for the alien container clip aliens .

Note  

Remember that the object returned by getBounds contains the properties xMin , xMax , yMin , and yMax .

Now we can switch on the aliens.direction to see which way our aliens are currently moving:

 switch(aliens.direction){           case 0: //right                if(b.xMax < Stage.width - rowOffset/2)                aliens._x += alienSpeed;                else{aliens.direction=1;ydist=rowOffset/2;}                break;           case 1: //down                if(ydist > 0){aliens._y += alienSpeed;ydist -= alienSpeed;}                else aliens.direction=2;                break;           case 2: //left                if(b.xMin > 0 + rowOffset/2) aliens._x -= alienSpeed;                else{aliens.direction = 3;ydist=rowOffset/2;}                break;           case 3: //down                if(ydist > 0){aliens._y += alienSpeed;ydist -= alienSpeed;}                else aliens.direction=0;                break;      } 

As you can see, we have a case for each direction. If the direction is 0, indicating moving to the right, we see if we've moved far enough. If not, we continue to move right and if so, we change the direction to 1, indicating a downward movement. When we change this, we set a variable called ydist , which allows us to know when we've moved down far enough and it's time to start moving left.

In the case to trap direction 1, we check to see if ydist as been reduced to 0. If it hasn't, we continue to move down and reduce ydist accordingly . If we've moved far enough, we change the direction to 2, which indicates a movement left.

This process goes on for the left direction and then for the downward direction again. After the four cases are complete, the aliens move back and forth across the stage, slowly approaching the user and his fragile spaceship.

Finally, we need a test to see if the aliens have advanced all the way to the bottom. When that happens, we want to hit the user's ship. If we hit the user's ship once each frame, the aliens are too low and the player dies within a matter of a few frames. That gives rise to the following script:

 if(b.yMax > ship._y)           hitShip(); 

This completes the alien's onEnterFrame handler as well as the implementation of the aliens. If you test the game now, you see something like Figure 6.26.

click to expand
Figure 6.26: The aliens are now moving about the stage.

The Bullets

We already have the bullet containers created and we have calls to fire them from firePlayerBullet and fireAlienBullet . Therefore, if we implement these two functions and then implement an onEnterFrame handler for each bullet type, bullets will be flying. Let's start with the alien bullets.

The Alien Bullets

We already have our function named from some previous code, so now we just have to fill in the implementation of the fireAlienBullet function. Let's have a look at that now.

The fireAlienBullet Function
 function fireAlienBullet(){ } 

The preceding script gives us a shell into which we can place the following script pieces.

First we need to find a random alien to fire our bullet. This is where our alienArray comes into play. We can run a loop that looks for a random alien in the array, and when it finds one, the loop stops. It's necessary to do this in a loop because when several aliens have been removed, the array contains empty spaces for them. In other words, some of the spaces in the alienArray contain values of undefined after the user has shot and killed a few. Let's look at the code to find a random alien in the array, assuming that some might be missing (dead):

 do{i = getRandom(0,alienArray.length);}      while(alienArray[i]==  undefined  ); 
Tip  

The previous script would have a problem if the user killed all the aliens because the do while loop would iterate forever. This doesn't happen because when an alien dies, there's a check inside the player's bullet code. If the alien that died is the last alien in the game, all the aliens are respawned before the dead alien array is scanned for a suitable shooter.

That should do it. We use a do while loop to pick a random alien from the array, and if it's undefined (dead), we keep picking. When this loop ends, we have a random alien with index i ready to shoot at the player.

Now we can attach a bullet. Remember that we're keeping the alien bullets in a container clip called alienBullets . To find a depth that isn't filled yet, let's use getNextHighestDepth on the target movie clip. After we attach the bullet, we move it under the alien:

 var bulletDepth = alienBullets.getNextHighestDepth()       var bullet = alienBullets.attachMovie("alienBullet",    " alienBullet"+ bulletDepth, bulletDepth);       bullet._x = alienArray[i]._x + aliens._x + 11;       bullet._y = alienArray[i]._y + aliens._y + 40; 

Now we're ready to give functionality to the bullet we just created. We do this by assigning it an onEnterFrame handler, which we name alienBulletEnterFrame , just like all the others:

 bullet.onEnterFrame = alienBulletEnterFrame; 

Finally, we need to set the fire delay so that the aliens can't fire again for several frames:

 aliens.fireDelay = alienFireDelay; 

That completes the fireAlienBullet function. We're now ready to implement the event handler for the bullets.

The alienBulletEnterFrame Function

To move the bullet, we need to change its position. That's simple enough, and it gives us a start to our alienBulletEnterFrame script, as follows:

 function alienBulletEnterFrame(){      this._y += alienBulletSpeed; } 

Now we need to see if the bullet has passed off the bottom of the stage. If it has, we remove it:

 if(this._y > Stage.height){           this.removeMovieClip();      } 

Finally, we need to hitTest against the player's ship so that we know if the bullet strikes the player. We can do that with the following script:

 if(ship.hitTest(this._x, this._y, true)){            hitShip();            this.removeMovieClip();      } 

As you can see, when the hitTest is true , we can call the hitShip function and then remove the bullet that just made contact. We'll define the hitShip function soon.

That's really all we need to do to handle the alien bullets. Let's move on to the player bullets because they are similar.

The Player Bullets

The player bullets are similar in concept to the alien bullets, so much of the script is similar. We first have the function firePlayerBullet to fire a bullet. Then we have the onEnterFrame handler for each bullet, which is called playerBulletEnterFrame . Let's look at each of these.

The firePlayerBullet Function

We need to do the same things here that we did with the alien bullet. First we attach the bullet clip at a unique depth:

 function firePlayerBullet(){      var bulletDepth = playerBullets.getNextHighestDepth()      var bullet = playerBullets.attachMovie("bullet",    " bullet"+ bulletDepth, bulletDepth); } 

Now that the bullet has been created, we can move it to the tip of the ship, where bullets are fired :

 bullet._x = ship._x;      bullet._y = ship._y; 

We need to give it an onEnterFrame handler:

 bullet.onEnterFrame = playerBulletEnterFrame; 

Finally, we need to set the frame delay for the ship so that the user cannot fire again for several frames. With the player's ship, we also need to disable the ship.fire function, which originally called the firePlayerBullet function:

 ship.fireDelay = fireDelay;      ship.fire = null; 
The playerBulletEnterFrame Function

As you've seen in the previous script, each bullet gets an onEnterFrame handler that calls the playerBulletEnterFrame function. We need to implement this function:

 function playerBulletEnterFrame(){ } 

This script is our function definition. Now we need to add script to that empty function. The first thing we need to do is move the bullet:

 this._y -= playerBulletSpeed; 

If the bullet has passed off the top of the stage, we're ready to remove it:

 if(this._y < 0){           this.removeMovieClip();      } 

Now we need to hit test this bullet against all the alien movie clips. The only snag here is that each alien is attached to the aliens container clip. That means that the aliens' coordinates are relative to that container clip. We must convert to the coordinate space of the aliens container clip before we hit test the aliens:

 p = new Object();      p.x = this._x;      p.y = this._y;      aliens.globalToLocal(p); 

Now we can create a for loop that iterates once for each alien in our alienArray . During each iteration, we hit test our bullet again that iteration's alien:

 for(var a = 0; a< alienArray.length; ++a){       al = alienArray[a];       if(p.x<al._x+al._width && p.x>al._x && p.y<al._y+al._width && p.y>al._y){       } } 

As you can see, I'm hit testing with my own script instead of a call to hitTest . Inside that if statement, we must put any script we need to handle an alien being shot. Several things are involved in this, including increasing the player's score:

 score+=al.scoreStep; 

We must also remove the reference from the alienArray :

 alienArray[a]=  undefined  ; 

Then we must remove the alien's movie clip from the stage:

 al.removeMovieClip(); 

From there, we must reduce our alien count to reflect one being killed:

 aliens.alienCount; 

Don't forget to remove the bullet so that only one alien dies:

 this.removeMovieClip(); 

Finally, we need a check to see if the entire batch of aliens has been killed. If it has, we need to move the player to the next level:

 if(aliens.alienCount == 0)           levelUp(); 

That completes our player bullet onEnterFrame handler. If you test the move now, everything should be able to fire bullets properly, as in Figure 6.27.

click to expand
Figure 6.27: The aliens can fire bullets at the player, and the player can fire his own bullets back.

We did make a call to getRandom , the function I've been using to generate random integers. So, make sure that it is in your source as follows:

 function getRandom(minimum, maximum){      return Math.floor(Math.random() * (maximum - minimum +1) + minimum); } 

The levelUp Function

This function is called when the player kills all the aliens:

 function levelUp(){      alienSpeed+=.5;      //make aliens faster      fireDelay -= 2;      //let player fire faster      alienFireDelay -= 2;      //make aliens fire faster      playerBulletSpeed += 2;      //increase player's bullet speed      alienBulletSpeed += 2;      //increase alien bullet speed      speed+=2;      //increase ship speed      level++;      //increase level by 1      score += 1000;      //score bonus for level completion      createAliens();     //create a new batch of aliens } 

As you can see, we're changing several of the game balance variables. We're speeding up both the aliens and the player. We conclude the function with a call to createAliens , which spawns a new batch of alien invaders for the player to kill.

The hitShip Function

Another function we've called but not implemented is the hitShip function, which handles an alien bullet hitting the player's ship. The hit testing was already done inside the alienBulletEnterFrame function, so we know when hitShip is called that there has been a collision:

 function hitShip(){       //increase red and decrease blue       ship.myColorTransform.rb += redStep;       ship.myColorTransform.bb -= redStep/2;       ship.myColor.setTransform(ship.myColorTransform);       //if our color is maxed out in red, the player dies       if(ship.myColorTransform.rb > 255)             killShip(); } 

This function is nothing more than a color transform of the ship. We're gradually removing the blue and adding red to the ship clip. When the red value is maxed, we call killShip .

Note  

The constant redStep increments the red coloring when the ship is hit. It's another of the constants we defined in initGame .

The killShip Function

We've just called killShip at the end of our hitShip function when the player's ship is completely red. We should implement killShip now, while we're on the subject:

 function killShip(){ } 

We need to do several things in this function. First we need to remove the player's control of his ship. We don't want him moving a dead ship around the stage after the game is over. It's easy enough to disable the controls because we've implemented them using event handlers. We can remove the event handlers to stop everything:

 ship.onKeyUp=null;      ship.onKeyDown=null;      ship.onEnterFrame=null;      aliens.onEnterFrame=null; 

Inside the key handlers, we used ship.left and similar variables to keep track of which keys the user pressed. We need to reset those now because with the key handlers gone, the user's keyUp events are forgotten. That might cause the user's ship to move without him pressing keys if he starts a new game. Let's clear out those keys now:

 ship.left=false;      ship.right=false;      ship.firing=false; 

We can attach the Game Over panel and set up the resetGame button attached to it:

 attachMovie("gameover"," gameover",gameoverDepth,{_x:Stage.width/2,_y:Stage.height/2});      gameover.resetButton.myText.text = "reset";      gameover.resetButton.onRelease = resetGame;      gameover.resetButton.stop(); 

That concludes the killShip function. When the user clicks the resetGame button, we call a function called resetGame , which is similar to initGame .

To implement the Game Over panel, we create a new symbol and add some text, telling the user he's dead. I've added another text field to show the user his score. There is a single button inside the symbol, and its instance name is resetButton . When the panel appears, the user must click this button to start a new game. After the gameover symbol is exported for ActionScript, the hitShip and killShip methods should work. This is confirmed when you test and is shown in Figure 6.28.

click to expand
Figure 6.28: The Game Over panel appears when the player dies.

The resetGame Function

This function is called when the user has died and has clicked the resetGame button on the Game Over panel.

 function resetGame(){ } 

We have several things to do in this function. First we want to reset all our game balance variables ”the ones we changed when the player cleared levels of aliens:

 speed = originalSpeed;      alienSpeed = originalAlienSpeed;      fireDelay = originalFireDelay;      alienFireDelay = originalAlienFireDelay;      playerBulletSpeed = originalPlayerBulletSpeed;      alienBulletSpeed = originalAlienBulletSpeed; 

Now we can create a new ship, aliens, and a scoreboard:

 createShip();      createAliens();      createScoreboard(); 

Finally, we need to remove the Game Over panel:

 this._parent.removeMovieClip(); 

That completes the implementation of the resetGame function.

The Stars

Our game looks a little cheesy right now because the ship and aliens are moving around on a solid black background. We could import a pretty bitmap graphic of space and put it behind everything ”maybe alpha blended ”to add atmosphere and give us a better look. The problem with that is we are moving vector graphics around all over the place. When you draw vector graphics on a bitmap and move the vector graphics around, Flash's rendering engine bogs down and your game plays at less than half the frame rate it should, even on fast computers. As a result, we're going to have to find another way to make our game look like it's occurring in outer space.

If we were to drag several small white dots on the screen randomly , it would give us the effect of stars. That's simple enough to implement. First we create a symbol that contains only a 1-pixel circle. We name it star and export it for ActionScript. Inside our initGame function, we make the following addition:

 createStars(); 

Now we have to implement this function:

 function createStars(){ } 

The first thing to do is create a container clip to organize our depths:

 createEmptyMovieClip("stars"," stars",starDepth); 

Now we create an initialization object:

 initObj = new Object(); 

After that, it's time to create the stars. Two hundred of them should be adequate:

 for(i=0;i<200;++i){           initObj._x = getRandom(0,Stage.width);           initObj._y = getRandom(0,Stage.height-30);           stars.attachMovie("star"," star"+i,i,initObj);      } 

As you can see, we generate a random position and then attach a star clip. This is done 200 times inside a for loop. Finally, when the loop ends, we don't need our initObject anymore, so we can delete it:

 delete initObject; 

That concludes our star implementation. If you test the movie, you should see the stars in the background, as in Figure 6.29.

click to expand
Figure 6.29: The randomly attached dots create a nice star effect.

Adding Sound

It's probably a good idea to be thinking about sound effects while you are building your games, but I often find myself neglecting this rule. Instead, I generally find myself near the end of implementation with a silent game. Then I must go back and sprinkle the sound script throughout.

I'm choosing to add the sound as the last step in this game because it would have only complicated the previous implementation to remark about the sound scripting everywhere it happens. Now you can see the sound as one implementation block, even if the script is actually sprinkled over the game's source code.

Before we can add sound to the game, we must import it into our Flash movie. Chapter 1 explains that process. After importing, you must change the linkage properties to export each sound for ActionScript. The sounds I'll be using in this game are called playerhit.wav, gameover.wav, deadalien.wav, warning.wav, and levelup.wav.

Two steps are involved in adding sounds to your game. The first step involves setting everything up. That means creating your Sound objects and attaching their respective sounds. The second step involves inserting calls to start and stop in your game script as appropriate.

The Sound Manager

Much like with the aliens and bullets, I'm going to use a container clip to help me organize my sounds. We'll use the standard createEmptyMovieClip function to do so. First let's think about our sound organization a bit.

To organize my sounds, I create a function called createSoundManager that does all the work necessary to initialize my sounds and set everything up. The last two lines in the initGame function should set a depth for our sound container clip and a call to our createSoundManager function:

 soundManagerDepth = 500; createSoundManager(); 

Now we implement this function:

 function createSoundManager(){ } 

The first thing to do inside this function is create a temporary variable to be used with some depth settings. This will make sense in a few moments:

 var soundDepth = 1; 

Now we create the sound container clip:

 createEmptyMovieClip("soundManager",soundManagerDepth); 

Notice that I've named the clip soundManager . From this point on, all our sounds will be children of this empty clip.

We're ready to create our first sound. The first thing to do is create another empty movie clip to associate this sound with. We could use an existing stage clip like the player's ship , but that might get confusing if we need more than one sound per object. Instead, we're going to create a fresh empty movie clip inside our soundManager clip:

 soundManager.createEmptyMovieClip("playerhit", soundDepth++); 

This, of course, creates an empty movie clip called playerhit , which is attached to the soundManager clip. Now we can create our sound object:

 soundManager.playerhit.mySound = new Sound(soundManager.playerhit); 

That creates a sound object attached to the playerhit object. The name of the sound object is mySound , and all our Sound objects will be named that. The difference between them is that each Sound object will be attached to its own empty movie clip.

Now that we have our sound object, we can call attachSound to bring in a sound from the library:

 soundManager.playerhit.mySound.attachSound("playerhit.wav"); 

That completes the playerhit sound. If we want to play it, we must call soundManager.playerhit.mySound.start(); . We're not ready to do that yet, though. Let's finish the rest of our sounds.

The following sounds are created identically to our first sound, playerhit . The only difference is that each has its own empty movie clip attached to soundManager and its own .wav to import from the library. The following script initializes the rest of our sounds:

 soundManager.createEmptyMovieClip("levelup", soundDepth++);      soundManager.levelup.mySound = new Sound(soundManager.levelup);      soundManager.levelup.mySound.attachSound("levelup.wav");      soundManager.createEmptyMovieClip("deadalien", soundDepth++);      soundManager.deadalien.mySound = new Sound(soundManager.deadalien);      soundManager.deadalien.mySound.attachSound("deadalien.wav");      soundManager.createEmptyMovieClip("warning", soundDepth++);      soundManager.warning.mySound = new Sound(soundManager.warning);      soundManager.warning.mySound.attachSound("warning.wav");      soundManager.warning.mySound.setVolume(50);      soundManager.createEmptyMovieClip("gameover", soundDepth++);      soundManager.gameover.mySound = new Sound(soundManager.gameover);      soundManager.gameover.mySound.attachSound("gameover.wav"); 

The only thing to notice is that I'm setting the volume of the warning sound to 50 percent. That's because the original sound was much louder than I wanted. I'm using Flash to compensate for this.

That completes our createSoundManager function. The only thing left to do is sprinkle our start calls throughout the rest of our game code.

Playing Our Sounds

As you know, we have five sound effects that we want to play. We'll handle them one at a time.

The playerhit Sound

This sound effect plays when an alien bullet hits the player. That's simple enough to implement. We can go into the hitShip function and add the following line of code:

 function hitShip(){  //play player hit sound   soundManager.playerhit.mySound.start();   //rest of the hitShip function  } 

And that's that. The playerhit sound plays one time: when the player's ship is hit.

The gameover Sound

This is another easy sound. We can go into the killShip function and add the following script:

 soundManager.gameover.mySound.start(); 
The deadalien Sound

Again, this sound is simple to implement. We go into the playerBulletEnterFrame function. Inside this function is the if statement, which does a collisions test with the aliens. Inside this if statement, when a collision is found, we add the following line:

 soundManager.deadalien.mySound.start(); 
The levelup Sound

This is the last of the simple sounds. Inside the levelup function, we add the following line:

 soundManager.levelup.mySound.start(); 
The warning Sound

This sound is a bit more complex. The idea is that when the player gets close to death, a warning sound plays repeatedly until he dies. This requires two things: a time to start the sound, and a time to end it. First we must begin the sound when the player is badly damaged. Inside the hitShip function, just before we test to see if the player is dead, we can add the following script:

 function hitShip(){      //play player hit sound      soundManager.playerhit.mySound.start();      //increase red and decrease blue      ship.myColorTransform.rb += redStep;      ship.myColorTransform.bb -= redStep/2;      ship.myColor.setTransform(ship.myColorTransform);  //if our color is close to max red, start playing the warning sound   if(ship.myColorTransform.rb > 200)   soundManager.warning.mySound.start(0,9999999);  //if our color is maxed out in red, player dies      if(ship.myColorTransform.rb > 255)           killShip(); } 

This script causes the warning sound to play infinitely (or nearly infinitely) when the player's red value exceeds 200.

Now we need to stop the warning when the player dies. We don't want the warning sound to be playing after the game is over, so in the killShip function, we add the following line:

 soundManager.warning.mySound.stop(); 

That completes the sound implementation. In future games, we'll use a similar strategy for sound effects.

Testing

After testing the first issue, I find that the user must click on the game once before he can control the ship. This only happens when viewing the movie in the browser, not in testing, because the movie does not have keyboard focus.

The second issue is that there are no instructions to tell the user which keys to use. We can solve both problems with an instruction menu that has a Start button.

This is easy enough to implement because of our modular design. The first thing to do is create a new symbol called instructions and add some text fields giving instructions to the user. Then add a button and name the instance startButton .

Now let's see the ActionScript to finish the implementation. We remove the single function call to initGame that is at the top of our script. We substitute it with a call to showInstructions , as follows:

 showInstructions(); 

Then we define this function:

 attachMovie("instructions"," instructions",gameoverDepth,{_x:Stage.width/2,    _y:Stage.height/2}); instructions.startButton.stop(); instructions.startButton.myText.text = "Start"; instructions.startButton.onRelease = function(){       initGame();       this._parent.removeMovieClip(); } 

This script creates a new instance of instructions and sets up the startGame button. When the button is released, initGame is called and the instructions instance is removed.

The beauty of this solution is that the user must now click the Start button to begin the game. That causes focus to be given to the movie inside the browser, giving the user control of his ship. Figure 6.30 shows the Instructions panel.


Figure 6.30: The Instructions panel tells the player which keys to use and requires him to click a button to give your movie focus.

Complete Code Listing

That's it for Critter Attack . Your code should look like the following, with all the code placed in frame 1 of the main timeline.

 //format the stage immediately Stage.align=" TL" Stage.scaleMode=" noScale" //single call to show the instructions showInstructions(); //function to show the user instructions. function showInstructions(){       attachMovie("instructions"," instructions",gameoverDepth,{_x:Stage.width/2,    _y:Stage.height/2});       instructions.startButton.stop();       instructions.startButton.myText.text = "Start";       instructions.startButton.onRelease = function(){            initGame();            this._parent.removeMovieClip();       } } //function to initialize the entire game. //Called only once when the movie first loads. function initGame(){       //depth settings       starDepth = 50;  //depth for the stars container clip       scoreboardDepth = 75;  //depth for the scoreboard       alienBulletsDepth = 98;   //depth for the alien bullet container clip       playerBulletDepth = 99;   //depth for the player bullet container clip       shipDepth = 100;   //depth for the player's ship       alienDepth = 101;  //depth for the alien container clip       gameoverDepth = 102;  //depth for the game over panel       soundManagerDepth = 500;  //depth for the sound manager clip       //Set up constants and game balance variables       //original versions are used to restore values when the game is reset       rowOffset = 50;  //used to offset the aliens vertically when we create them       colOffset = 65;  //used to offset the aliens horizontally when we create them       originalSpeed = speed = 12;  //ship speed       originalAlienSpeed = alienSpeed = 1;  //speed the aliens move       originalFireDelay = fireDelay = 16;  //frame delay for the player's laser       originalAlienFireDelay = alienFireDelay = 15;  //frame delay for the aliens    to fire       originalPlayerBulletSpeed = playerBulletSpeed = 20;  //speed of the    player's bullets       originalAlienBulletSpeed = alienBulletSpeed = 10;  //speed of the alien bullets       redStep = 20;  //amount of red to add when player is shot       createScoreboard();  //create and initialize the scoreboard       createAliens();  //create alien container and the aliens       createShip();   //create the player's ship       createStars();   //create the background stars.       createSoundManager();   //create the sound manager } /////////////////////////////// //create the sound manager function createSoundManager(){       var soundDepth = 1;       createEmptyMovieClip("soundManager",soundManagerDepth);       soundManager.createEmptyMovieClip("playerhit", soundDepth++);       soundManager.playerhit.mySound = new Sound(soundManager.playerhit);       soundManager.playerhit.mySound.attachSound("playerhit.wav");       soundManager.createEmptyMovieClip("levelup", soundDepth++);       soundManager.levelup.mySound = new Sound(soundManager.levelup);       soundManager.levelup.mySound.attachSound("levelup.wav");       soundManager.createEmptyMovieClip("deadalien", soundDepth++);       soundManager.deadalien.mySound = new Sound(soundManager.deadalien);       soundManager.deadalien.mySound.attachSound("deadalien.wav");       soundManager.createEmptyMovieClip("warning", soundDepth++);       soundManager.warning.mySound = new Sound(soundManager.warning);       soundManager.warning.mySound.attachSound("warning.wav");       soundManager.warning.mySound.setVolume(50);       soundManager.createEmptyMovieClip("gameover", soundDepth++);       soundManager.gameover.mySound = new Sound(soundManager.gameover);       soundManager.gameover.mySound.attachSound("gameover.wav"); } ////////////////////////// //create the stars on the background function createStars(){       //create starts container       createEmptyMovieClip("stars"," stars",starDepth);       //initialization object       initObj = new Object();       //create 200 stars       for(i=0;i<200;++i){             //get a random position             initObj._x = getRandom(0,Stage.width);             initObj._y = getRandom(0,Stage.height-30);             //attach a star clip             stars.attachMovie("star"," star"+i,i,initObj);       }       delete initObject;  //we don't need the initObject anymore } /////////////////////////////// //reset the game after the player has been killed function resetGame(){       //reset the game balance variables       speed = originalSpeed;       alienSpeed = originalAlienSpeed;       fireDelay = originalFireDelay;       alienFireDelay = originalAlienFireDelay;       playerBulletSpeed = originalPlayerBulletSpeed;       alienBulletSpeed = originalAlienBulletSpeed;       //create a new ship, aliens, and scoreboard       createShip();       createAliens();       createScoreboard();       //remove the Game Over panel       this._parent.removeMovieClip(); } ////////////////////////////// //Call this funciton when the ship gets hit by an alien or alien bullet function hitShip(){       //play player hit sound       soundManager.playerhit.mySound.start();       //increase red and decrease blue       ship.myColorTransform.rb += redStep;       ship.myColorTransform.bb -= redStep/2;       ship.myColor.setTransform(ship.myColorTransform);       //if our color is close to max red, start playing the warning sound       if(ship.myColorTransform.rb > 200)             soundManager.warning.mySound.start(0,9999999);       //if our color is maxed out in red, player dies       if(ship.myColorTransform.rb > 255)             killShip(); } ///////////////////////////////// //call this function when the player dies function killShip(){       //play the game over sound       soundManager.gameover.mySound.start();       //stop the warning sound from playing anymore       soundManager.warning.mySound.stop();       //remove all the event handlers for aliens and the ship       ship.onKeyUp=null;       ship.onKeyDown=null;       ship.onEnterFrame=null;       aliens.onEnterFrame=null;       //release movement keys       ship.left=false;       ship.right=false;       ship.firing=false;       //attach a game over panel       attachMovie("gameover"," gameover",gameoverDepth,{_x:Stage.width/2,    _y:Stage.height/2});       //initialize the reset button on the game over panel       gameover.resetButton.myText.text = "reset";       gameover.resetButton.onRelease = resetGame;       gameover.resetButton.stop(); } /////////////////////////////////// //create and initialize the scoreboard function createScoreboard(){       attachMovie("scoreboard"," scoreboard",scoreboardDepth, {_y:Stage.height});       score = 0;       level = 1; } ////////////////////////////////////// //call to fire a player bullet function firePlayerBullet(){       //set up a delay so that the player cannot fire again for fireDelay frames       ship.fireDelay = fireDelay;       //remove fire function from player so he can't fire       ship.fire = null;       var bulletDepth = playerBullets.getNextHighestDepth()       //attach a new bullet to the bullet container       var bullet = playerBullets.attachMovie("bullet",    " bullet"+ bulletDepth, bulletDepth);       //move the bullet       bullet._x = ship._x;       bullet._y = ship._y;       //set the bullet's onEnterFrame handler       bullet.onEnterFrame = playerBulletEnterFrame; } //////////////////////////////// //function that a player bullet calls every frame function playerBulletEnterFrame(){       //move bullet up       this._y -= playerBulletSpeed;       //if bullet is off the stage, remove it       if(this._y < 0){             this.removeMovieClip();       }       //use p to convert a point from global to local space for hit testing       p = new Object();       p.x = this._x;       p.y = this._y;       aliens.globalToLocal(p);       //for each alien       for(var a = 0; a< alienArray.length; ++a){            al = alienArray[a];            //hit test the alien            if(p.x<al._x+al._width && p.x>al._x && p.y<al._y+al._width && p.y>al._y){                 //play dead alien sound                 soundManager.deadalien.mySound.start();                 //increase score                 score+=al.scoreStep;                 //remove the alien's entry in the array                 alienArray[a]=  undefined  ;                 //remove the alien movie clip                 al.removeMovieClip();                 aliens.alienCount;                 //remove this bullet                 this.removeMovieClip();                 //check whether all aliens are dead                 if(aliens.alienCount == 0)                       levelUp();            }       } } ///////////////////////////////////// //call to cause the aliens to fire a bullet function fireAlienBullet(){       //find a random alien that has not been shot       do{i = getRandom(0,alienArray.length);}       while(alienArray[i]==  undefined  );       var bulletDepth = alienBullets.getNextHighestDepth()       //attach an alien bullet and place it under this alien       var bullet = alienBullets.attachMovie("alienBullet",    " alienBullet"+ bulletDepth, bulletDepth);       bullet._x = alienArray[i]._x + aliens._x + 11;       bullet._y = alienArray[i]._y + aliens._y + 40;       //assign the alien functionality       bullet.onEnterFrame = alienBulletEnterFrame;       //set the alien fire delay so the aliens don't shoot       //again for alienFireDelay frames       aliens.fireDelay = alienFireDelay; } /////////////////////////////////// //function that each alien bullet calls every frame function alienBulletEnterFrame(){       //move bullet down       this._y += alienBulletSpeed;       //if bullet is off stage, remove it       if(this._y > Stage.height){             this.removeMovieClip();       }       //hit test the player's ship       if(ship.hitTest(this._x, this._y, true)){             //if there is a collision with the player, hit player's ship             hitShip();             //remove this bullet             this.removeMovieClip();       } } //////////////////////////////////////// //call when all the aliens are dead function levelUp(){       alienSpeed+=.5;  //make aliens faster       fireDelay -= 2;  //let player fire more quickly       alienFireDelay -= 2;  //make aliens fire more quickly       playerBulletSpeed += 2;  //increase player's bullet speed       alienBulletSpeed += 2;  //increase alien's bullet speed       speed+=2;  //increase ship speed       level++;  //increase level by 1       score += 1000;   //score bonus for level completion       createAliens();  //create a new batch of aliens       soundManager.levelup.mySound.start(); //play the level up sound } /////////////////////////////////////////// //Create an alien container and fill it with aliens function createAliens(){       //create an array for the aliens       alienArray = new Array();       //create a container clip for the aliens       createEmptyMovieClip("aliens",alienDepth);       aliens.alienCount=0;       //use initialization object       initObj = new Object();       initObj._xscale = 30;       initObj._yscale = 30;       //5 rows of aliens       for(rows=0;rows<5;++rows){            switch(rows){                  //pick which alien type goes in this row                  case 0: alienNumber=2; break;                  case 1: alienNumber=4; break;                  case 2: alienNumber=1; break;                  case 3: case 4: alienNumber=3; break;            }            //7 columns of aliens of this type            for(cols=0;cols<7;++cols){                  //assign scores for each alien                  initObj.scoreStep = (6-rows) * 100;                  //move each alien to its position                  initObj._x = cols*colOffset+colOffset/2;                  initObj._y = rows*rowOffset+rowOffset/2;                  //create the alien movie clip and push a reference to it into the array                  alienArray.push(aliens.attachMovie("alien"+alienNumber,    " alien"+aliens.alienCount, aliens.alienCount++,initObj));            }       }       delete initObj; //dispose of our initialization object       //assign the aliens an enterFrame handler       aliens.onEnterFrame = alienEnterFrame;       //start the aliens moving to the right       aliens.direction = 0;       //create a container for the alien bullets       createEmptyMovieClip("alienBullets",alienBulletsDepth); } ////////////////////////////////////// //function that the aliens call every frame function alienEnterFrame(){       //see if the aliens are delayed from firing       if(aliens.fireDelay > 0)            aliens.fireDelay;       //if not, fire a bullet       else fireAlienBullet();       var b = new Object();       b = aliens.getBounds(_root);       switch(aliens.direction){            case 0: //right                  if(b.xMax < Stage.width - rowOffset/2)                  aliens._x += alienSpeed;                  else{aliens.direction=1;ydist=rowOffset/2;}                  break;            case 1: //down                  if(ydist > 0){aliens._y += alienSpeed;ydist -= alienSpeed;}                  else aliens.direction=2;                  break;            case 2: //left                  if(b.xMin > 0 + rowOffset/2) aliens._x -= alienSpeed;                  else{aliens.direction = 3;ydist=rowOffset/2;}                  break;            case 3: //down                  if(ydist > 0){aliens._y += alienSpeed;ydist -= alienSpeed;}                  else aliens.direction=0;                  break;       }       if(b.yMax > ship._y)            hitShip(); } /////////////////////////////////////// //call to create a new player ship function createShip(){       attachMovie("ship"," ship",shipDepth,{_x:Stage.width/2,_y:Stage.height- 65,_xscale:18,_yscale:18});       ship.flame._visible=false;       ship.onKeyUp=shipKeyUp;       ship.onKeyDown=shipKeyDown;       ship.onEnterFrame=shipEnterFrame;       ship.fire = firePlayerBullet;       Key.addListener(ship);       ship.myColor = new Color(ship);       ship.myColorTransform = {rb:0, bb:0};       createEmptyMovieClip("playerBullets",playerBulletDepth); } /////////////////////////////////// //function called by the player ship every frame function shipEnterFrame(){       if(ship.left && this._x>15+speed && ship.left^ship.right) this._x-=speed;       else if(ship.right && this._x<Stage.width-15-speed &&    ship.left^ship.right) this._x+=speed;       if(ship.fireDelay > 0)            ship.fireDelay;       else ship.fire = firePlayerBullet;       if(ship.firing) ship.fire(); } /////////////////////////////////////// //event handler for a key going down function shipKeyDown(){       k=Key.getCode();       if(k==Key.LEFT) ship.left=true;       else if(k==Key.RIGHT) ship.right = true;       else if(k==Key.SPACE){ship.firing=true; ship.fire();}       if(ship.left^ship.right)ship.flame._visible=true;       else ship.flame._visible=false; } /////////////////////////////////////////// //event handler for a key going up function shipKeyUp(){       k=Key.getCode();       if(k==Key.LEFT) ship.left=false;       else if(k==Key.RIGHT) ship.right=false;       else if(k==Key.SPACE) ship.firing=false;       if(!ship.left && !ship.right) ship.flame._visible=false;       else            ship.flame._visible=true; } ///////////////////////////////////// //function to generate a random integer between minimum and maximum inclusive function getRandom(minimum, maximum){       return Math.floor(Math.random() * (maximum - minimum +1) + minimum); } 



Macromedia Flash MX 2004 Game Programming
Macromedia Flash MX 2004 Game Programming (Premier Press Game Development)
ISBN: 1592000363
EAN: 2147483647
Year: 2004
Pages: 161

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net