Without a scoring system, few games would have much replay value. Trying to break your old high score keeps you coming back for more. In this section you'll add scoring to the game. You will also give the player limited lives.
The first thing you need to do is create a text cast member that will be used to display the score. Depending on the font you use, you'll also want to embed the numbers from the font to be sure the text is displayed as you intended it.
Make the assets cast active, and choose Insert > Media Element > Font. Choose Arial as the Original Font option, change the font type to Bold from Plain, and choose Entire Set, as shown. Click the OK button when you're done. Ariel is such a popular font that you probably don't actually need to embed it, but it's still a good idea when you can't be sure someone viewing your movie will have the font installed. When you click OK to dismiss the dialog you will see the new font appear in the assets cast as Arial Bold *. (If you don't have Arial installed on your system, choose some other font.)
In the Score, click frame 10 of channel 34 to select the frame. Choose the Text tool in the Tool Palette, and drag out a text field on the Stage. Enter a 0 into the field, then double-click the text sprite that has appeared in the Score to open it for editing.
You created the text in channel 34 so that it would appear in front of other sprites.
Because you don't know how wide the text area needs to be in order to display thescore, you can enter a large number such as 999,999,999 into the field, change the widthto fit the number, and then change the number back to 0.
Within the text window that opens, enter the name score for the text member's name, and choose Align Right for the formatting. Double-click the text to select it, set the font size to 18 points, and change the color to something like bright yellow. Make sure the font being used is set to Arial Bold *.
Close the text window and click the text sprite to select it. Using the Property inspector, change the sprite's ink type to Background Transparent. Position the score display sprite in the upper-right corner of the Stage. Finally, modify the sprite's span length so it ends at frame 65.
With a place to display the score, you just need to add the necessary Lingo that will increment the score whenever an enemy is destroyed.
Select the internal cast and double-click the Main Script to open it for editing. Add the following two lines to the end of the startMovie handler:
_global.theScore = 0 doScore(0)
The reason you used theScore instead of just score is because "score" is a Lingo term in Director, also known as a reserved word. You actually use the reserved word, but it's best to avoid doing that. It's good practice to use variable names that aren't part of Lingo.
The second line calls the doScore method, with 0 as a parameter. Although the method doesn't exist yet (you will create it next) this line is there in order to be sure the score displays as 0 when the movie starts.
Next, you will add code to the enemy behaviors that will increment and display the score when the enemy is destroyed. You could handle this in a couple of different ways. For example, you could increment and display the score directly within the behavior. But what if you changed the name of your text member displaying the score? You'd need to go through and change the code anywhere the score was updated.
Instead of modifying the score within the behavior, it's better to create a method within the movie script that can be called from anywhere the score should be modified. This way, if you change anything, you need only change the code in one location.
Add the following method within the Main Script:
on doScore addScore _global.theScore = _global.theScore + addScore member("score").text = string(_global.theScore) end
Can you see how this will work? If you want to increase the score by 100 points all you need to use is doScore(100) within your code. The score will be incremented by 100 and displayed in the score text cast member.
Right-click one of the enemy ship sprites in level 1 and select Script from the context menu. Add the following line of Lingo to the explode method:
doScore(100 * _global.theLevel)
In level 1, each enemy ship will be worth 100 points; in level 2 it will be worth 200 points, and so on.
Close the script window and right-click one of the asteroids in level 3. Select script from the context menu, and add the same line of code to the behavior's explode method:
doScore(100 * _global.theLevel)
Now, whenever one of the enemy ships (or an asteroid) is destroyed, the score will be increased and displayed.
The last thing left to do in this section is to give the player a set number of lives, usually three to five, and decrement it as necessary.
Adding the Remaining Lives
There are a couple of ways to display the number of lives remaining. You could use a simple text field, like you did with the score. Or you could use icons to represent the number of player ships remaining. For our game we'll use copies of a scaled-down version of the player's ship itself to show how many lives remain:
Click frame 10 of channel 35 to select it, then drag member ship1 from the assets cast onto the Stage. To make it smaller, drag the new sprite by one of its corner handles while holding down the Shift key.
It doesn't really matter what size you make the icon, so long as it's fairly small. Holding the Shift key while scaling the sprite locks the sprite's aspect ratio so its proportions don't change.
Position the icon in the upper-left corner of the Stage. Click the sprite's span to select it and press Ctrl/Command+C to copy it. Click frame 10 of channel 36 and press Ctrl/Command+V to paste in the copied sprite. Finally, select both icons in channels 35 and 36 and click in the frame bar at frame 80. Press Ctrl/Command+B to extend both sprites.
The two icons are now in place and represent the player ships remaining in reserve: a total of three ships, counting the one in the game. You can now add the necessary Lingo to keep track of the lives remaining, and modify the icon display.
Double-click the Main Script in the internal cast to open it for editing. Add the declaration for the global variable lives to the startMovie handler, and then create the doLives method.
Within the startMovie handler add the following two lines of Lingo:
_global.lives = 3 doLives()
Next, create the doLives method within the script:
on doLives case _global.lives of 3: sprite(35).visible = true sprite(36).visible = true 2: sprite(35).visible = true sprite(36).visible = false 1: sprite(35).visible = false sprite(36).visible = false end case end
When the doLives method is called, the visibility of sprites 35 and 36 will be altered accordingly. If all three lives are available, which they are at the start, both icons visible property will be set to true. If just one life remains, both icons will be set to invisible, so the only ship remaining is the one actually in the game.
All you need to do now is decrement the lives variable when the player loses a life, and call doLives to show the change. If you decrement the lives variable and have zero lives remaining, you'll instead want to jump to a "game over" section.
Right-click the player's ship and select Script from the context menu. Add the following Lingo within the repeat loop that checks for collisions. You can add this code immediately after the line that plays the boom sound.
_global.lives = _global.lives - 1 if _global.lives = 0 then _movie.go("gameOver") else doLives() end if
When a collision is detected for the player's ship, the global variable lives will be decremented by 1. If there is at least one life left, the doLives method is called, which updates the icons representing the remaining ships. If no lives remain the movie jumps to the gameOver marker (which doesn't exist yet, but it will).
Close the script window and create the gameOver marker at frame 90. Choose the assets cast, then import gameOver.png from the Lesson13\media folder on the CD. Import the image with 32 bits so the alpha channel stays intact.
You can now place the new cast member into the game over section of the game.
Drag the newly imported bitmap and drop it into channel 1 of the Score so that it appears centered on the Stage. Drop it so that the sprite's span begins at frame 90, then adjust the span so it ends at frame 95.
With the graphic in place you can add the code to check for "y" or "n" being processed.
Select the internal cast and double-click the Score's behavior channel at frame 95. Create the following frame behavior:
on keyDown me if _key.keyPressed(16) then --y _movie.go("intro") startMovie() end if if _key.keyPressed(45) then --n _movie.halt() end if end on exitFrame me _movie.go(_movie.frame) end
When the game ends if you press y to play again, the movie is sent to the intro marker and the startMovie handler is called, which initializes the global variables to their initial states. If the n key is pressed, the halt command stops the movie.
Let's do one more quick thing before moving on. Adding a transition to the transition channel will allow you to reveal the game over image in a more interesting way than just cutting to it.
Name the script gameOver and close the script window. If the Score's effects channels aren't showing, right-click in the frame bar and select Effects Channels from the context menu. Double-click the transition channel at frame 90 to open the Frame Properties: Transition dialog:
You place a transition effect on the frame you're going to. The transition will then happen between that frame and whatever frame you came from.
There are many different transitions you can pick from the list. Shown here is the Dissolve, Pixels transition, which will do a sort of pixelated dissolve between the two frames.
Choose the Dissolve, Pixels transition and set the Duration slider to 1.00 seconds. Press OK to close the dialog.
Note that the transition appears in the active cast as a new cast member. You can double-click it in the cast to open its properties dialog for editing, and you can also drag and drop it into the transition channel of other frames.
Modify the span of the text sprite in channel 34it's used to display the scoreso it ends at frame 95.
Why do that? Because when the game is over, you want players to still be able to see their score.
Save the movie before continuing.
In the next section you'll add a little more Lingo in order to check the global enemyList to see when it's empty, and move on to the next level when it is.
Currently, if you shoot down all the enemies on a level nothing happens, aside from your earning some points. What you need is to move to a new level. When you kill all the enemy ships on level 1, you need to jump to level 2, then level 3, and finally level 4 before starting over with faster enemies.
You can use the global enemyList, which stores the sprite numbers of all the enemy ships on a level, to know when the level is cleared. Each ship removes itself from the list when it has been destroyed, so the list will be empty when all ships have been destroyed. Want to know when a level is cleared? Just check to see if the list is empty after removing a ship from it.
Right-click one of the enemy ship sprites in level 1 and select Script from the context menu. Add the following line of Lingo to the behavior's enterFrame handler.
if _global.enemyList =  then go next
This line of Lingo needs to be placed inside the conditional test to see if explodeCount has reached 20. When it has, the sprite's locV is set to -2000 to move it off Stage, and its cast member is set to origMember. When completed, the conditional, with the new line will look like the following:
if exploding then explodeCount = explodeCount + 1 if explodeCount = 20 then sp.locV = -2000 sp.member = origMember exploding = false if _global.enemyList =  then go next end if end if
When you issue the go next command, the playhead jumps to the next marker in the Score, no matter what frame the marker is at. If there is no next marker, the playhead will jump to the closest previous marker.
Although you could place the check within the explode method, right after the sprite's number is removed from the enemyList, placing it here ensures that the explosion will be displayed before the game jumps to the next level.
Because the enemy ships on levels 1 and 2 share the same behavior, you don't need to do anything with the UFOs on level 2. But you will need to add the check for the empty enemyList to the asteroid's behavior so you can get to level 4.
Right-click one of the asteroids in level 3 and select Script from the context menu. Add the line that checks for the empty enemyList immediately after the line that sets the sprite's cast member back to its original member. The line goes in the same spot it did in the enemy ship behavior:
if _global.enemyList =  then go next
Of course, the problem here is that the next marker is currently the gameOver marker at frame 90. You'll fix that in the next, and last, section of this lesson when you add the final level to the game.
Before doing that, one final thing needs to be done when changing levels. Right now, when you clear a level of enemies you will appropriately jump to the next level. However, you also need to increment the global variable theLevel so that as you go up in levels, the enemies respond by speeding up. The most direct way of doing that is to add a line of code to the clear enemy list behavior attached to the first frame of each level.
Double-click the behavior channel at frame 10 to open the clear enemy list behavior. Add the following line to the beginSprite handler to increment the global variable:
_global.theLevel = _global.theLevel + 1
Because this behavior is attached to the first frame of all three levels, the variable will be incremented whenever you jump to a new level. You should be aware that the variable theLevel is initialized to 1 in the startMovie handler, so it will be incremented to 2 at the start of level 1. You can choose to go back and initialize theLevel to 0, or you can leave it as is. The only effect it will have is to cause the enemy ships on level 1 to move a little faster.