This is the second installment in our Corona SDK Bloons inspired Game tutorial. In today's tutorial, we'll add to our interface and start coding the game interaction. Read on!
Where We Left Off. . .
Please be sure to check part 1 of the series to fully understand and prepare for this tutorial.
Step 1: Declare Functions
Declare all functions as local at the start.
local Main = {} local startButtonListeners = {} local showCredits = {} local hideCredits = {} local showGameView = {} local gameListeners = {} local startCharge = {} local charge = {} local shot = {} local onCollision = {} local startGame = {} local createBalloons = {} local update = {} local restartLvl = {} local alert = {} local restart = {}
Step 2: Constructor
Next, we'll create the function that will initialize all the game logic:
function Main() -- code... end
Step 3: Add Title View
Now we place the TitleView in the stage and call a function that will add the tap listeners to the buttons.
titleBg = display.newImage('titleBg.png') playBtn = display.newImage('playBtn.png', display.contentCenterX - 25.5, display.contentCenterY + 40) creditsBtn = display.newImage('creditsBtn.png', display.contentCenterX - 40.5, display.contentCenterY + 85) titleView = display.newGroup(titleBg, playBtn, creditsBtn) startButtonListeners('add')
Step 4: Start Button Listeners
This function adds the necesary listeners to the TitleView buttons.
function startButtonListeners(action) if(action == 'add') then playBtn:addEventListener('tap', showGameView) creditsBtn:addEventListener('tap', showCredits) else playBtn:removeEventListener('tap', showGameView) creditsBtn:removeEventListener('tap', showCredits) end end
Step 5: Show Credits
The credits screen is shown when the user taps the about button. A tap listener is added to the credits view to remove it.
function showCredits:tap(e) playBtn.isVisible = false creditsBtn.isVisible = false creditsView = display.newImage('credits.png') transition.from(creditsView, {time = 300, x = -creditsView.width, onComplete = function() creditsView:addEventListener('tap', hideCredits) creditsView.x = creditsView.x - 0.5 end}) end
Step 6: Hide Credits
When the credits screen is tapped, it'll be tweened out of the stage and removed.
function hideCredits:tap(e) playBtn.isVisible = true creditsBtn.isVisible = true transition.to(creditsView, {time = 300, x = -creditsView.width, onComplete = function() creditsView:removeEventListener('tap', hideCredits) display.remove(creditsView) creditsView = nil end}) end
Step 7: Show Game View
When the Start button is tapped the title view is tweened and removed, revealing the game view.
function showGameView:tap(e) transition.to(titleView, {time = 300, x = -titleView.height, onComplete = function() startButtonListeners('rmv') display.remove(titleView) titleView = nil startGame() end}) -- Add GFX infoBar = display.newImage('infoBar.png', 0, 276) restartBtn = display.newImage('restartBtn.png', 443, 286) squirrel = display.newImage('squirrel.png', 70, 182) gCircle = display.newImage('gCircle.png', 83, 216) gCircle:setReferencePoint(display.CenterReferencePoint) targetTF = display.newText('0', 123, 287, native.systemFontBold, 14) targetTF:setTextColor(238, 238, 238) scoreTF = display.newText('0', 196, 287, native.systemFontBold, 14) scoreTF:setTextColor(238, 238, 238) acornsTF = display.newText('5', 49, 287, native.systemFontBold, 13) acornsTF:setTextColor(238, 238, 238) end
Step 8: Game Listeners
This code adds tap listeners to the game background. These will be used to shoot the acorns to the balloons. A tap listener is also added to the restart button.
function gameListeners(action) if(action == 'add') then bg:addEventListener('touch', startCharge) bg:addEventListener('touch', shot) restartBtn:addEventListener('tap', restartLvl) Runtime:addEventListener('enterFrame', update) else bg:removeEventListener('touch', startCharge) bg:removeEventListener('touch', shot) restartBtn:removeEventListener('tap', restartLvl) Runtime:removeEventListener('enterFrame', update) end end
Step 9: Start Game
Here we start the game by hiding the direction indicator, adding the game listeners and calling the function that generates the balloons.
function startGame() -- Hide gCircle gCircle.isVisible = false -- Create balloon function gameListeners('add') createBalloons(5, 3) end
Step 10: Create Balloons
A double for loop is used to create and place the balloons on the stage. The balloon is then added to a table. This will grant us access to the balloons outside this function.
function createBalloons(h, v) for i = 1, h do for j = 1, v do local balloon = display.newImage('balloon.png', 300 + (i * 20), 120 + (j * 30)) balloon.name = 'balloon' physics.addBody(balloon) balloon.bodyType = 'static' table.insert(balloons, balloon) end end -- Set balloon counter targetTF.text = #balloons end
Step 11: Collisions
This function handles the acorn-balloon collisions.
When this occur, the balloon is removed from the stage and a sound is played. We also update the score and target textfields.
function onCollision(e) if(e.other.name == 'balloon') then display.remove(e.other) e.other = nil audio.play(pop) scoreTF.text = scoreTF.text + 50 scoreTF:setReferencePoint(display.TopLeftReferencePoint) scoreTF.x = 196 targetTF.text = targetTF.text - 1 end if(targetTF.text == '0') then alert('win') end end
Step 12: Start Charge
This code will reveal the direction indicator, reset the acorn's impulse variable, and add a frame listener that will handle the aim and impulse value.
function startCharge:touch(e) if(e.phase == 'began') then impulse = 0 gCircle.isVisible = true Runtime:addEventListener('enterFrame', charge) end end
Step 13: Charge
The aim rotates accordingly to the direction that will take the acorn, which is set by the impulse variable.
function charge() gCircle.rotation = gCircle.rotation - 3 impulse = impulse - 0.2 -- Prevent over rotation if(gCircle.rotation < -46) then gCircle.rotation = -46 impulse = -3.2 end end
Step 14: Code Review
Here is the full code written in this tutorial, alongside with the comments to help you identify each part:
-- Balloons Physics Game -- Developed by Carlos Yanez -- Hide Status Bar display.setStatusBar(display.HiddenStatusBar) -- Physics local physics = require('physics') physics.start() -- Graphics -- [Background] local bg = display.newImage('gameBg.png') -- [Title View] local titleBg local playBtn local creditsBtn local titleView -- [Credits] local creditsView -- [Game View] local gCircle local squirrel local infoBar local restartBtn -- [TextFields] local scoreTF local targetTF local acornsTF -- Load Sound local pop = audio.loadSound('pop.mp3') -- Variables local titleView local credits local acorns = display.newGroup() local balloons = {} local impulse = 0 local dir = 3 -- Functions local Main = {} local startButtonListeners = {} local showCredits = {} local hideCredits = {} local showGameView = {} local gameListeners = {} local startCharge = {} local charge = {} local shot = {} local onCollision = {} local startGame = {} local createBalloons = {} local update = {} local restartLvl = {} local alert = {} local restart = {} -- Main Function function Main() titleBg = display.newImage('titleBg.png') playBtn = display.newImage('playBtn.png', display.contentCenterX - 25.5, display.contentCenterY + 40) creditsBtn = display.newImage('creditsBtn.png', display.contentCenterX - 40.5, display.contentCenterY + 85) titleView = display.newGroup(titleBg, playBtn, creditsBtn) startButtonListeners('add') end function startButtonListeners(action) if(action == 'add') then playBtn:addEventListener('tap', showGameView) creditsBtn:addEventListener('tap', showCredits) else playBtn:removeEventListener('tap', showGameView) creditsBtn:removeEventListener('tap', showCredits) end end function showCredits:tap(e) playBtn.isVisible = false creditsBtn.isVisible = false creditsView = display.newImage('credits.png') transition.from(creditsView, {time = 300, x = -creditsView.width, onComplete = function() creditsView:addEventListener('tap', hideCredits) creditsView.x = creditsView.x - 0.5 end}) end function hideCredits:tap(e) playBtn.isVisible = true creditsBtn.isVisible = true transition.to(creditsView, {time = 300, x = -creditsView.width, onComplete = function() creditsView:removeEventListener('tap', hideCredits) display.remove(creditsView) creditsView = nil end}) end function showGameView:tap(e) transition.to(titleView, {time = 300, x = -titleView.height, onComplete = function() startButtonListeners('rmv') display.remove(titleView) titleView = nil startGame() end}) -- Add GFX infoBar = display.newImage('infoBar.png', 0, 276) restartBtn = display.newImage('restartBtn.png', 443, 286) squirrel = display.newImage('squirrel.png', 70, 182) gCircle = display.newImage('gCircle.png', 83, 216) gCircle:setReferencePoint(display.CenterReferencePoint) targetTF = display.newText('0', 123, 287, native.systemFontBold, 14) targetTF:setTextColor(238, 238, 238) scoreTF = display.newText('0', 196, 287, native.systemFontBold, 14) scoreTF:setTextColor(238, 238, 238) acornsTF = display.newText('5', 49, 287, native.systemFontBold, 13) acornsTF:setTextColor(238, 238, 238) end function gameListeners(action) if(action == 'add') then bg:addEventListener('touch', startCharge) bg:addEventListener('touch', shot) restartBtn:addEventListener('tap', restartLvl) Runtime:addEventListener('enterFrame', update) else bg:removeEventListener('touch', startCharge) bg:removeEventListener('touch', shot) restartBtn:removeEventListener('tap', restartLvl) Runtime:removeEventListener('enterFrame', update) end end function startGame() -- Hide gCircle gCircle.isVisible = false -- Create balloon function gameListeners('add') createBalloons(5, 3) end function createBalloons(h, v) for i = 1, h do for j = 1, v do local balloon = display.newImage('balloon.png', 300 + (i * 20), 120 + (j * 30)) balloon.name = 'balloon' physics.addBody(balloon) balloon.bodyType = 'static' table.insert(balloons, balloon) end end -- Set balloon counter targetTF.text = #balloons end function onCollision(e) --if(e.other.name == 'balloon' and e.phase == 'ended') then if(e.other.name == 'balloon') then display.remove(e.other) e.other = nil audio.play(pop) scoreTF.text = scoreTF.text + 50 scoreTF:setReferencePoint(display.TopLeftReferencePoint) scoreTF.x = 196 targetTF.text = targetTF.text - 1 end if(targetTF.text == '0') then alert('win') end end function startCharge:touch(e) if(e.phase == 'began') then impulse = 0 gCircle.isVisible = true Runtime:addEventListener('enterFrame', charge) end end function charge() gCircle.rotation = gCircle.rotation - 3 impulse = impulse - 0.2 -- Prevent over rotation if(gCircle.rotation < -46) then gCircle.rotation = -46 impulse = -3.2 end end
Next Time...
In the next and final part of the series, we'll handle the acorn shooting, level restart, and the final steps to take prior to release like app testing, creating a start screen, adding an icon and, finally, building the app. Stay tuned for the final part!
Comments