|
Want to thank me for making this book available for free? Just buy Special Edition Using Macromedia Director MX
Advanced Lingo For Games
| |
| Making the Game
As mentioned before, all the game code is contained in one long frame behavior. This makes it very easy to implement this game with just the one behavior and a collection of bitmaps. The property declarations have useful descriptions after them, with the exception of the parameters that are defined in the on getPropertyDescriptionList handler. -- Parameters property pFirstSprite, pLastSprite property pGloveSprite property pSpeed property pDropFrequency property pCatchRequirement, pCatchDistance property pScoreIncrement property pEndGameCondition, pEndGameNumber property pCatchBadPenalty property pDropSound, pCatchSound property pMissSound, pBadCatchSound property pEndGameFrame -- Other Properties property pScore -- Player Score property pUsingSprites -- Sprites currently in the action property pNumberMissed -- Number of good objects missed property pNumberBadCaught -- Number of bad objects caught property pNextDropTime -- next time an object is scheduled to fall This behavior contains the longest on getPropertyDescriptionList handler that we have seen so far in this book. Thus, this game is highly customizable. I've scattered some additional comments inside the handler text that follows. Figure 8.2 shows the resulting Parameters dialog box.
Figure 8.2
The Parameters dialog box for the falling objects game has quite a few customizable parameters.
on getPropertyDescriptionList me
list = [:]
-- First sprite with object
addProp list, #pFirstSprite,[cc]
[#comment: "First Sprite",[cc]
#format: #integer,[cc]
#default: 11]
-- last sprite with object
addProp list, #pLastSprite,[cc]
[#comment: "Last Sprite",[cc]
#format: #integer, #default: 20]
The last two parameters tell the behavior where the sprites in the score are located that will be used as the falling objects. You can put in as few or as many of these as you want. The game will not try to assign more falling objects at one time than there are sprites. So, if you want to limit the number of items that can be falling at once to eight, only have eight sprites available.
-- sprite that catches objects
addProp list, #pGloveSprite,[cc]
[#comment: "Glove Sprite",[cc]
#format: #integer,[cc]
#default: 5]
-- starting speed of fall
addProp list, #pSpeed,[cc]
[#comment: "Speed",[cc]
#format: #integer,[cc]
#default: 5]
The "pSpeed" property sets the number of pixels that each falling object moves for each frame. Another important factor in the speed of the game is the Score tempo. Make sure you set the Score tempo to something like 15 or 30 frames per second before playing around with the "pSpeed" parameter. Try to keep the tempo constant as you adjust "pSpeed". In most games, the speed of the game is determined by both the behavior parameters, like "pSpeed" and the Score's tempo. On fast machines, you can use a low parameter value, and a high tempo to make a smooth game. However, slower machines may not be able to keep up with the high tempo of the movie. If you want your game to work fast on slower machines, use a high behavior parameter such as "pSpeed", and a low tempo. Experiment with different values on both a low-speed test machine and your high-speed development computer.
-- how often to drop objects
addProp list, #pDropFrequency,[cc]
[#comment: "Drop Frequency",[cc]
#format: #integer,[cc]
#default: 60]
This property can be confusing because a lower number means that objects fall more often. More precisely, it is the number of ticks that must pass before another object falls.
-- test to be performed to determine catch
addProp list, #pCatchRequirement,[cc]
[#comment: "Catch Requirement",[cc]
#format: #string,[cc]
#range: ["Rects Touch", "Loc Inside Rect",[cc]
"Rect Touches Loc", "Square Distance",[cc]
"Circular Distance"],[cc]
#default: "Loc Inside Rect"]
The "pCatchRequirement" parameter sometimes needs an accompanying number value to define it. This number is used in case either of the distance methods are chosen. The "pCatchDistance" parameter is used for that. If neither of the distance methods are used, the "pCatchDistance" parameter is ignored.
-- distance measurement for catch test
addProp list, #pCatchDistance,[cc]
[#comment: "Catch Distance (If Needed)",[cc]
#format: #integer,[cc]
#default: 20]
The next parameter determines how many points are awarded for each correct catch, as well as how many points should be subtracted for an incorrect catch.
-- how many points to be awarded for each catch
addProp list, #pScoreIncrement,[cc]
[#comment: "Score Increment",[cc]
#format: #integer,[cc]
#default: 10]
Like the "pCatchRequirement", the "pEndGameCondition" needs a number value to fully define the end game condition. In the case of the first two choices, this number is used to determine how many objects must be missed, or caught, to end the game. In the case of the "Obtain Certain Score" choice, the number is used as the score that must be obtained.
-- how does the game end
addProp list, #pEndGameCondition,[cc]
[#comment: "End Game Condition",[cc]
#format: #string,[cc]
#range: ["Miss Number of Good Objects",[cc]
"Catch Number of Bad Objects",[cc]
"Obtain Certain Score"],[cc]
#default: "Miss Number of Good Objects"]
-- number associated with the end game condition
addProp list, #pEndGameNumber,[cc]
[#comment: "End Game Number",[cc]
#format: #integer,[cc]
#default: 3]
The next parameter allows you to specify if you want points to be subtracted when the player catches the wrong object.
-- what happens when a bad item is caught
addProp list, #pCatchBadPenalty,[cc]
[#comment: "Catch Bad Item Penalty",[cc]
#format: #string,[cc]
#range: ["Nothing",[cc]
"Lose Points"],[cc]
#default: "Nothing"]
The next four parameters are the sounds to be used in the game. If you leave them blank, no sound is played at all.
-- sound to play when item drops
addProp list, #pDropSound,[cc]
[#comment: "Drop Sound",[cc]
#format: #string,[cc]
#default: ""]
-- sound to play when item is caught
addProp list, #pCatchSound,[cc]
[#comment: "Catch Sound",[cc]
#format: #string,[cc]
#default: ""]
-- sound to play when item is missed
addProp list, #pMissSound,[cc]
[#comment: "Miss Sound",[cc]
#format: #string,[cc]
#default: ""]
-- sound to play when bad item is caught
addProp list, #pBadCatchSound,[cc]
[#comment: "Bad Catch Sound",[cc]
#format: #string,[cc]
#default: ""]
The last parameter is the frame to which the movie advances when the game is over.
-- Frame to go to when game is over
addProp list, #pEndGameFrame,[cc]
[#comment: "End Game Frame",[cc]
#format: #marker,[cc]
#default: #next]
return list
end
The on beginSprite handler resets all the score-like properties, clear the pUsingSprites list and set the value of the score text on the screen. -- reset score and sprite list on beginSprite me pScore = 0 pNumberMissed = 0 pNumberBadCaught = 0 pNextDropTime = the ticks showScore(me) pUsingSprites = [] end All action in the game takes place in the on exitFrame handler. First, the glove sprite is aligned to match the current cursor position. Then, each falling object is moved down a bit. Next, all the objects are checked to see if any have been caught. Finally, the time is checked to see if another object should drop.
-- regularly timed events
on exitFrame me
-- match glove sprite to cursor
sprite(pGloveSprite).locH = the mouseH
-- move objects down
letObjectsFall(me)
-- see if an object has been caught
checkCaught(me)
-- see if another item can be dropped
if the ticks > pNextDropTime then
dropObject(me)
pNextDropTime = the ticks + pDropFrequency
end if
-- loop on the frame
go to the frame
end
The "on letObjectsFall" handler loops through the sprites in use and moves them down according to "pSpeed"{1}. If the sprite has passed out of view on the bottom of the screen, then the sprite is recycled by removing it from the "pUsingSprites" list{2}. A check is also made to see if the object is a "good" object. If so, then it was missed by the player and gets added to the "pNumberMissed" property{3}. If the game is set to end when the player misses a certain number of good objects, then the "on checkEndGame" handler is called to end the game.
-- move all existing objects down
on letObjectsFall me
repeat with i = pUsingSprites.count down to 1
-- get sprite number
s = pUsingSprites[i]
-- get vertical location
y = sprite(s).locV
-- increase vertical location
y = y + pSpeed{1}
sprite(s).locV = y
if y > (the stage).rect.height + sprite(s).rect.height/2 then
-- sprite is beyond bottom of screen, remove object
if sprite(s).member.name = "Good" then
if pMissSound <> "" then puppetSound pMissSound
pNumberMissed = pNumberMissed + 1{3}
showScore(me)
checkEndGame(me)
end if
deleteAt pUsingSprites, i{2}
end if
end repeat
end
When it is determined that it's time to drop a new object, the "on dropObject" handler is called. This handler first loops through the sprite range to find a sprite not being used{4}. Then, it assigns it a random member from the cast library of objects. It also picks a random horizontal location and a vertical location that puts the object just above the top of the screen.
-- create a new falling object
on dropObject me
-- loop through sprites
repeat with s = pFirstSprite to pLastSprite
-- see if it is being used
if not getOne(pUsingSprites,s) then{4}
-- pick a random member
r = random(the number of members of castLib "Objects")
mem = member(r,"Objects")
-- random horizontal location that still
-- has entire member on the screen
screenWidth = (the stage).rect.width
memberWidth = mem.rect.width
x = random(screenWidth-memberWidth)+memberWidth/2
-- set vertical loc to just above screen
memberHeight = mem.rect.height
sprite(s).loc = point(x,-memberHeight/2)
-- set member
sprite(s).member = mem
-- add to list
add pUsingSprites, s
-- no need to look further
if pDropSound <> "" then puppetSound pDropSound
exit repeat
end if
end repeat
end
The "on checkCaught" handler checks each sprite that is in use and determines if it has been caught by the glove. It uses one of the five methods to determine this, depending on the "pCatchRequirement" parameter. If a catch has been made, the "on checkCaught" handler must deal with it being either a good object or a bad one. In the latter case, the "pNumberBadCaught" must be incremented{5}. If it's a good catch, "on addScore" is called{6}. Either way, the "on checkEndGame" handler must be called.
-- check to see if any objects were caught
on checkCaught me
repeat with i = pUsingSprites.count down to 1
s = pUsingSprites[i]
if pCatchRequirement = "Rects Touch" then
if sprite s intersects pGloveSprite then
catch = TRUE
end if
else if pCatchRequirement = "Loc Inside Rect" then
if inside(sprite(s).loc, sprite(pGloveSprite).rect) then
catch = TRUE
end if
else if pCatchRequirement = "Rect Touches Loc" then
if inside(sprite(pGloveSprite).loc, sprite(s).rect) then
catch = TRUE
end if
else if pCatchRequirement = "Square Distance" then
if (sprite(s).locH - sprite(pGloveSprite).locH) <= pCatchDistance and[cc]
(sprite(s).locV - sprite(pGloveSprite).locV) <= pCatchDistance then
catch = TRUE
end if
else if pCatchRequirement = "Circular Distance" then
if sqrt(power(sprite(s).locH - sprite(pGloveSprite).locH,2)+[cc]
power(sprite(s).locV - sprite(pGloveSprite).locV,2))[cc]
<= pCatchDistance then
catch = TRUE
end if
end if
if catch then
sprite(s).locV = -30
deleteOne pUsingSprites, s
if sprite(s).member.name = "Good" then
if pCatchSound <> "" then puppetSound pCatchSound
addScore(me){6}
else
if pBadCatchSound <> "" then puppetSound pBadCatchSound
if pCatchBadPenalty = "Lose Points" then
subtractScore(me)
end if
pNumberBadCaught = pNumberBadCaught + 1{5}
showScore(me)
end if
checkEndGame(me)
end if
end repeat
end
If a catch has been made, the score increases, and the drop frequency decreases. -- add to the score and increase drop frequency on addScore me pScore = pScore + pScoreIncrement pDropFrequency = pDropFrequency - 1 showScore(me) end If a bad object has been caught, and the "pBadCatchPenalty" is set to "Lose Points", then the "on subtractScore" handler is used to decrease the score. Care is given not to allow the score to fall below zero. If you prefer not to take pity upon bad players, you can remove that line and let the score fall into negative values.
-- subtract points
on subtractScore me
pScore = pScore - pScoreIncrement
if pScore < 0 then
-- donŐt allow score to go under 0
pScore = 0
end if
showScore(me)
end
The "on showScore" handler works as it did for earlier games, but has an addition here. If the "pEndGameCondition" is set to "Miss Number of Good Objects", then the "pNumberMissed" is shown as well as the score. If the "pEndGameCondition" is set to "Catch Number of Bad Objects", then the "pNumberBadCaught" is shown. Either helps the user determine how close he or she is to the end of the game, thus adding a little tension to the gameplay.
-- update the onscreen text member
on showScore me
text = "Score:"&&pScore&RETURN
-- add second line depending on the type of game
if pEndGameCondition = "Miss Number of Good Objects" then
put "Objects Missed:"&&pNumberMissed after text
else if pEndGameCondition = "Catch Number of Bad Objects" then
put "Bad Objects:"&&pNumberBadCaught after text
end if
member("score").text = text
end
The "on checkEndGame" looks at each of the three possible ways the game can end, and goes to a new frame if any are true. You might want to make it so the game can end on a combination of the end game conditions, rather than just one. A little modification of the code could have this handler ignore the "pEndGameCondition" property and instead just check for all the conditions.
-- see if the necessary game over condition is met
on checkEndGame me
if pEndGameCondition = "Miss Number of Good Objects" then
if pNumberMissed >= pEndGameNumber then
go to frame pEndGameFrame
end if
else if pEndGameCondition = "Catch Number of Bad Objects" then
if pNumberBadCaught >= pEndGameNumber then
go to frame pEndGameFrame
end if
else if pEndGameCondition = "Obtain Certain Score" then
if pScore >= pEndGameNumber then
go to frame pEndGameFrame
end if
end if
end
| |