Now that the ship is happily flying about the screen under your control, you'll want to give it the ability to shoot at the enemy ships. For a true arcade-like feeling, the ship needs to be able to fire rapidly and without interruption.
There are several ways you could accomplish this, including using imaging Lingo, but we're going to use a more traditional approach sometimes called a sprite magazine, or sprite clip.
The technique involves "loading" a predetermined number of channels with bullets, and then placing the bullets off Stage. As bullets are fired, they are moved on Stage to the ship's position and animated across the screen. On each successive shot, the next bullet in the magazine is used until the end is reached, where the clip simply loops back around to start at the first bullet. As long as you have just enough bullets in your magazine it will appears as if you're able to shoot a continuous stream of bulletsand essentially you can.
However if you don't have enough bullets in your clip then they will be reused before making it off the screen, resulting in something like this:
Finding the right number is a matter of trial and error, and will depend on the speed of your bullets, the size of your Stage, the space between bullets, etc. I ended up with ten bullets for this game, with 150 milliseconds between each bullet. Let's see how this works.
Go to the assets cast and import bullet.png from the Lesson12\media folder on the CD. Be sure to import the image using 32 bits per pixel so you retain the transparency.
This is just a tiny 8x8 pixel bitmap, a blue dot with a red dot inside of it, but it makes a good enough bullet.
Drag the bullet from the cast into the Score. Drop it so that it is in channel 22 and begins at frame 10. Adjust the span so that it ends at frame 25, the end of Level 1.
This will, of course, be the first bullet in your clip. The clip itself will occupy channels 22 to 31, for a total of ten bullets.
Select the bullet sprite by single clicking it and press Ctrl/Command+C to copy it. Click at frame 10 of channel 23, then press Ctrl/Command+V to paste in the copied sprite. Continue until you have a total of ten bullets occupying channels 22 to 31, as shown:
With the bullets loaded into the clip you can create the behavior that will animate the bullet across the screen after it is fired.
Choose the internal cast so that the new script is created there. Right-click the first bullet sprite in the Score in channel 22, and select Script from the context menu. Replace the default mouseUp handler with the following script:
property sp, lastTime, moveAmount, moving on beginSprite me sp = sprite(me.spriteNum) sp.locH = -20 moveAmount = 900 / 2.0 / 1000 moving = false end on shoot me moving = true sp.loc = sprite("player").loc + point(45,3) lastTime = _system.milliseconds end on enterFrame me if moving then currTime = _system.milliseconds timePassed = currTime - lastTime amtToMove = timePassed * moveAmount sp.locH = sp.locH + amtToMove if sp.locH > 820 then moving = false end if lastTime = _system.milliseconds end if end
You should recognize much of this code from the behaviors you created for the enemy ships. With slight differences, they do essentially the same thing, moving the bullet based on the elapsed time between frames.
First, a reference to the sprite is created and stored in the sp property. The bullet is then moved off the Stage, by setting its locH property to -20. Remember, the beginSprite handler runs before the frame is drawn so you will never see the bullets in their starting position when the movie is running. The amount to move per milliseconds is then calculated and stored in the moveAmount property. Finally, moving is set to false, indicating the bullet is currently not moving.
The shoot method, which follows, readies the bullet and will be called whenever the space bar is pressed to fire a bullet. First, the moving property is set to true. This is a flag variable used by the enterFrame handler that follows. Next, the bullet is placed at the nose of the ship using an offset of 45 pixels to the right and 3 pixels down from the ship's center point. I arrived at point (45, 3) by trial and error, but free to try out any different numbers you like.
The lastTime property is then initialized to the current value of the milliseconds, which will be used for the time-based animation within the enterFrame handler.
Within the enterFrame handler the moving property is first checked to see if it is true. If it is, the rest of the code executes, moving the bullet. As with the enemy ships, the elapsed time is calculated by subtracting the last time from the current time. This is then multiplied by the amount to move per millisecond, which gives you the total distance to move. This is then added to the sprite's current locH, which moves the bullet across the screen to the right. A check is performed to see if the bullet has left the Stage by moving beyond the 820-pixel mark. If it has, the moving property is set to false so that the sprite doesn't continue to animate.
When the bullet is needed again, its shoot method will be called, placing the bullet back at the front of the ship, and resetting the moving property to true.
Name the script bullet_move and close the script window. Select the bullet sprites, in the Score, in channels 23 through 31 by single-clicking the sprite in channel 23 and then Shift-clicking the sprite in channel 31. Don't select the first bullet, in channel 22. Drag the bullet_move script from the internal cast and drop it onto the group of selected bullets.
All the bullet sprites now have the bullet_move behavior attached. You're ready for a test.
Rewind and play the movie and open the Message window. Enter the following then press Enter to execute it:
As soon as you press Enter a bullet is shot from the front of the shipyahoo! Go ahead and execute the same line again, or try shooting a different sprite. You can see that all you need to do is call the shoot method, using sendSprite, whenever the space bar is pressed. To do this you need to add another key test to the frame behavior in order to test for the space barthe trigger, as it were.
Double-click the Main Script and add the following initialization for the bulletChannel global variable, to the startMovie handler:
_global.bulletChannel = 22
This variable is your index into the sprite clip, and is initialized to the channel containing the first bullet, which is 22. This variable will be used by the frame behavior so that it knows which bullet to fire.
Double-click the frame behavior at frame 25 to open it for editing. Begin by adding the global declaration, and property declaration at the very top of the script, as well as the new beginSprite handler:
global bulletChannel property bulletTime on beginSprite me bulletTime = _system.milliseconds + 150 end
Because the bulletChannel variable will be used many times, it's easier to define it once at the top of the script. The bulletTime property will be used to add a slight spaceabout 150 millisecondsbetween successive bullets.
Within the enterFrame handler, add the following conditional test for the space bar. Add this test after the other four tests for the cursor keys:
if _key.keyPressed(49) then if _system.milliseconds > bulletTime then sendSprite(bulletChannel, #shoot) bulletChannel = bulletChannel + 1 if bulletChannel > 31 then bulletChannel = 22 bulletTime = _system.milliseconds + 150 end if end if
If the space bar is pressed the current value of the milliseconds is checked to see if it's greater than the bulletTime property. If it is, the sendSprite method calls the shoot handler of the bullet defined by the bulletChannel variable. Because bulletChannel is initially 22, as set in the startMovie handler, the first bullet in the clip is shot. The bulletChannel is then incremented by one, and then tested to see if it is greater than 31. If it is, the end of the clip has been reached and the variable is reset back to 22, causing the clip to loop. The bulletTime property is then set to the current value of the milliseconds plus 150, in order to create a slight space between bullets.
Now, as long as the space bar is pressed, or even held down, a bullet will be fired every 150 milliseconds. Let's see how it works.
Rewind and play the movie. Navigate the ship using the cursor keys while firing bullets using the space bar. Hold down the space bar to fire a continuous stream of bullets.
Pretty cool, right? And it gets better. In the next lesson you'll learn about detecting collisions so that the bullets will destroy the enemy shipsand those ships will destroy you if they hit you.
Before moving on, you should copy the bullet sprites and paste them into the other two levels.
Stop the movie and single-click the first bullet sprite in channel 22 of the Score. Shift-click the last bullet in channel 31 to select all the bullets. Press Ctrl/Command+C to copy the sprites. Click in the Score at frame 30 of channel 22 and press Ctrl/Command+V to paste the bullet sprites into Level 2. Click again at frame 50 of channel 22 and paste the bullets into Level 3.
Although it would've been possible to simply extend the sprite spans of the bullets to occupy all three levels, by doing it this way the beginSprite handler will be called at the start of each level, causing the bullets to be removed from the Stage.
Be sure to save the movie to your local project_three folder before continuing.
That's it for this lesson. Before moving on, you might want to try removing the 150-millisecond pause between bullets to gauge the effect. You can do this easily by resetting bulletTime to just the current value of the milliseconds, and not tack on the additional 150.