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