In this tutorial series we will create a Whack-a-Groundhog game. The objective of the game is tap on the groundhogs before they disappear. Read on!
Where We Left Off...
In the previous part of this series we added the game background and began animating our groundhogs. In this the final part of the series, we will implement the gameplay, options, and start screen of our app, and then end up with a complete game!
1. setupGameScreen()
As the game is now, the groundhogs animate forever and do not seem to go back inside their holes. We need to add some more keys to our sequenceData
to fix this. Add the following within the setupGameScreen()
function:
local sequenceData = { {name="show", start=2 , count = 3,time=800,loopCount=1,loopDirection="bounce"}, {name = "blank",start=1,count=1}, {name = "hit1",start=5,count=1}, {name = "hit2", start=6,count=1}, {name = "hit3", start=7,count=1} }
The "blank" sequence is a blank transparent image which is part of the sprite sheet, and the "hit1", "hit2", and "hit3" sequences are 3 different "hit" states of the groundhog. Look at the "groundhogsheet.png" image to see this for yourself.
Make sure you set the loopCount
equal to 1 on the "show" sequence.
Now change the following code block:
tempGroundHog:setSequence("blank") tempGroundHog:addEventListener('tap', groundHogHit);
Here we have set the sequence to "blank" and have added a tap listener to the groundhog sprite.
Next, remove the following line of code:
tempGroundHog:play()
If you test now, none of the groundhogs should be animating. We will soon be getting a random groundhog animating!
2. groundHogHit()
When the groundhog is tapped we will determine whether or not it was out of its hole. If so, we will change its sequence to one of the three hit states that we added in the previous step.
Add the following inside the groundHogHit()
function:
local thisSprite = e.target thisSprite:removeEventListener( "sprite", groundHogSpriteListener ) local function hide() thisSprite:setSequence("blank") end if(thisSprite.sequence == "show") then local randomIndex = math.random(3) thisSprite:setSequence("hit"..randomIndex) timer.performWithDelay(1000, hide) end
Here we reference the Sprite that was clicked by e.target
and remove its Event Listener. We then check if its sequence is equal to "show". If it is, we generate a number between 1 and 3 and set its sequence equal to "hit"..randomIndex
. All this does is generate the strings "hit1", "hit2", or "hit3". Finally, we call the local hide function after 1000 milliseconds which sets the Sprites sequence to "blank".
3. getRandomGroundHog()
The getRandomGroundHog()
function gets a random groundhog and allows it to begin animating. Enter the following inside the getRandomGroundHog() function
:
local randomIndex = math.random(#allGroundHogs) local randomGroundHog = allGroundHogs[randomIndex] if(randomGroundHog.sequence ~="blank") then getRandomGroundHog() else randomGroundHog:addEventListener( "sprite",groundHogSpriteListener ) randomGroundHog:setSequence("show") randomGroundHog:play() end
Here we get a randomIndex
from the allGroundHogs
table. Next, we set the randomGroundHog
equal to the index. We then check if its sequence does not equal "blank", and, if it doesn't, we call getRandomGroundHog()
again. Otherwise, we add the groundHogSpriteListener
to set its sequence to "show" and play the sequence.
4. groundHogSpriteListener()
The groundHogSpriteListener()
checks if the "show" sequence has finished playing. If so, it sets it to the "blank" sequence. Enter the following within the groundHogSpriteListener()
:
local thisSprite = event.target --"event.target" references the sprite if ( event.phase == "ended" ) then if(thisSprite.sequence == "show") then thisSprite:setSequence("blank") end -- a half second delay end
5. Animating Random GroundHogs
With all the above in place we get random groundhogs animating. Add the following to the bottom of thesetUpGameScreen()
function:
groundHogTimer = timer.performWithDelay(groundHogSpeed, getRandomGroundHog,0)
If you test now you should see the groundhogs randomly popping out of their holes. While you are there, try clicking on the groundhogs while they are out of their holes. You should see one of the 3 hit states, and then the blank state.
When you are done testing, remove the line you just entered. We only needed it for testing.
6. setUpIntroScreen()
In this step we will begin to setup the intro screen. Enter the following code inside the setUpIntroScreen
function:
media.playSound("gameTrack.mp3",soundComplete) introScreenGroup = display.newGroup() local titleScreen = display.newImage("titleScreen.png") local playButton = display.newImage("playButton.png",100,100) local optionsButton = display.newImage("optionsButton.png",100,170) introScreenGroup:insert(titleScreen) introScreenGroup:insert(playButton) introScreenGroup:insert(optionsButton)
Here we start the soundtrack, setup the intro screen, and add the playButton
and optionsButton
graphics.
Now call the setUpIntroScreen()
function beneath where you are calling the setUpGameScreen()
function..
setUpGameScreen() setUpIntroScreen()
If you test now you should see the Intro Screen. We need to add Event Listeners to the buttons and that is what we'll do in the next steps.
7. Play Button Listener
Enter the following beneath the code you entered in the step above:
playButton:addEventListener("tap",function () transition.to(introScreenGroup, {time = 300, x = -480, onComplete = function() groundHogTimer = timer.performWithDelay(groundHogSpeed, getRandomGroundHog,0) end }) isPlaying = true end )
When the play button is pressed, we animate the intro screen off to the left, set our groundHogTimer
to generate random groundhogs, and then set the isPlaying
variable to true.
If you test now, you should be able to start a new game, but we would like some options to be available as well. We'll do that next.
8. Options Button Listener
Enter the following beneath the code you entered in the step Above.
optionsButton:addEventListener("tap", function() transition.to(optionsScreenGroup, {time = 300, y = 0, onComplete = function() introScreenGroup. x = -480 end }) end )
This code animates the option screen down from above. When the animation is complete, it puts the introScreenGroup
off of the main screen to the left.
If you test now and press the options button you'll not see anything happen, and that is because we have not yet created the options screen.
9. setUpOptionsScreen()
Enter the following inside the setUpOptionsScreen()
function:
optionsScreenGroup = display.newGroup() local optionsScreen = display.newImage("optionsScreen.png") local backButton = display.newImage("backButton.png",130,240) local soundOnText = display.newText( "Sound On/Off", 75,105, native.systemFontBold, 16 ) local groundHogSpeedText = display.newText("Speed", 75,145,native.systemFontBold,16) optionsScreenGroup:insert(optionsScreen) optionsScreenGroup:insert(backButton) optionsScreenGroup:insert(soundOnText) optionsScreenGroup:insert(groundHogSpeedText) optionsScreenGroup.y = -325
Here we setup the optionsScreen
, add the backButton
, and add a couple of texts.
Now call this function beneath where you are calling setUpIntroScreen
:
setUpIntroScreen() setUpOptionsScreen()
If you test the game now you should see the options screen slide down from above.
10. soundCheckBox
We will be using the checkbox widget to allow the user to turn on/off the sound. Enter the following at the very top of the "main.lua" file.
local widget = require( "widget" )
To be able to use the Switch and other widgets we must first require the "widget" module
Now enter the following beneath the code you entered above in the setUpOptionsScreen
.
local soundCheckBox = widget.newSwitch { left = 210, top = 98, style = "checkbox", initialSwitchState = true, onPress = function(e) local check = e.target if(check.isOn) then media.playSound("gameTrack.mp3",soundComplete) else media.stopSound() end end } optionsScreenGroup:insert(soundCheckBox)
This sets up our checkbox widget by setting "style" equal to "checkbox". We check if the checkbox isOn
(if it is selected), and if so we play the "gameTrack.mp3". If not, we stop the sound.
If you test now and go to the options screen, you should be able to turn the sound on or off.
11. speedControl
We use a SegmentedControl to allow the user to choose how fast the groundHogs should appear. Enter the following beneath the code for the checkbox you entered in the step above:
local speedControl = widget.newSegmentedControl { left = 210, top = 140, segments = { "slow", "medium", "fast"}, segmentWidth = 50, defaultSegment = 1, onPress = function(event) local target = event.target if(target.segmentNumber == 1)then groundHogSpeed = 1500 elseif (target.segmentNumber == 2)then groundHogSpeed = 1000 else groundHogSpeed = 700 end end } optionsScreenGroup:insert(speedControl)
Here we create a SegmentedControl with 3 segments ("slow","medium","fast"). Depending on which segment the user has pressed we set the groundHogSpeed
variable accordingly.
If you test now you should see the SegmentedControl and be able to select a segment, but we need to wire up the back button to get back to the intro screen.
12. backButton
The backButton
takes us back to the intro screen. Enter the following code beneath the above step:
backButton:addEventListener("tap", function() if(isPlaying == false)then introScreenGroup.x = 0 end transition.to(optionsScreenGroup, {time = 300, y = -325, onComplete = function() if(isPlaying == true) then groundHogTimer = timer.performWithDelay(groundHogSpeed, getRandomGroundHog,0) end end }) end )
Here we check whether the game has started. If not, we put the introScreenGroup
back into the playing area. We then transition the options screen back up. If the game has started, we set the groundHogtimer
to generate random groundhogs.
13. setUpGameScreen() - Adding Options
We need to be able to get to the options screen from the main game screen. Add the following beneath where you are inserting the gameBackground
into the gameScreenGroup()
.
gameScreenGroup:insert(gameBackground) local optionsButton = display.newImage("optionsButton.png",1,270) gameScreenGroup:insert(optionsButton)
If you test now you should see the options button on the game screen.
Now we need to wire up the options button with an EventListener. To do so, enter the following code beneath the loop that creates all the groundhogs.
optionsButton:addEventListener("tap", function(e) timer.cancel(groundHogTimer) transition.to(optionsScreenGroup, {time = 300, y = 0, onComplete = function() end }) end )
Here we cancel the groundHogTimer
and transition our options screen down.
Testing now, you should be able to get to the options screen from the game screen. You should also be able to set the options as desired.
14. soundComplete()
If you have played long enough for the soundtrack to finish, you may have noticed it did not start over. Enter the following within the soundComplete()
function.
media.playSound( "gameTrack.mp3", soundComplete )
This just starts the soundtrack playing again once it completes.
Conclusion
In this series, we learned how to create a fun and interesting Whack-a-Groundhog game. In doing so, you've learned how to utilize sprite sheets and sound. I hope you found this tutorial useful, and thanks for reading!
Comments