This is the second installment in our Corona SDK Rapid Roll 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 placeBet = {}
local randomShellMove = {}
local checkMovesLeft = {}
local revealBall = {}
local alert = {}
Step 2: Constructor
Next, we'll create the function that will initialize all the game logic:
function Main() addTitleView() 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.
function addTitleView()
bg = display.newImage('bg.png')
title = display.newImage('titleBg.png')
startB = display.newImage('startBtn.png')
startB.x = display.contentCenterX
startB.y = display.contentCenterY
startB.name = 'startB'
creditsB = display.newImage('creditsBtn.png')
creditsB.x = display.contentCenterX
creditsB.y = display.contentCenterY + 60
creditsB.name = 'creditsB'
titleView = display.newGroup()
titleView:insert(title)
titleView:insert(startB)
titleView:insert(creditsB)
initialListeners('add')
end
Step 4: Start Button Listeners
This function adds the necesary listeners to the TitleView buttons.
function initialListeners(action)
if(action == 'add') then
startB:addEventListener('tap', gameView)
creditsB:addEventListener('tap', showCredits)
else
startB:removeEventListener('tap', gameView)
creditsB:removeEventListener('tap', showCredits)
end
end
Step 5: Show Credits
The credits screen is shown when the user taps the credits button, a tap listener is added to the credits view to remove it.
function showCredits()
credits = display.newImage('creditsView.png')
transition.from(credits, {time = 400, x = display.contentWidth * 2, transition = easing.outExpo})
credits:addEventListener('tap', hideCredits)
startB.isVisible = false
creditsB.isVisible = false
end
Step 6: Hide Credits
When the credits screen is tapped, it'll be tweened out of the stage and removed.
function hideCredits()
startB.isVisible = true
creditsB.isVisible = true
transition.to(credits, {time = 600, x = display.contentWidth * 2, transition = easing.outExpo, onComplete = destroyCredits})
end
function destroyCredits()
credits:removeEventListener('tap', hideCredits)
display.remove(credits)
credits = nil
end
Step 7: Remove Title View
When the Start button is tapped, the title view is tweened and removed revealing the game view.
function gameView()
initialListeners('rmv')
-- Remove MenuView, Start Game
transition.to(titleView, {time = 500, y = -titleView.height, onComplete = function()display.remove(titleView) titleView = nil addInitialBlocks(3)end})
Step 8: Score & Lives Text
This code creates the Score and Lives text and places them in the stage.
-- Score Text
scoreTF = display.newText('0', 303, 22, system.nativeFont, 12)
scoreTF:setTextColor(68, 68, 68)
-- Lives Text
livesTF = display.newText('x3', 289, 56, system.nativeFont, 12)
livesTF:setTextColor(245, 249, 248)
end
Step 9: Add Initial Blocks
The following function adds the blocks specified in the parameter at a random position, it will also call the function to add the player to the stage.
function addInitialBlocks(n)
blocks = display.newGroup()
for i = 1, n do
local block = display.newImage('block.png')
block.x = math.floor(math.random() * (display.contentWidth - block.width))
block.y = (display.contentHeight * 0.5) + math.floor(math.random() * (display.contentHeight * 0.5))
physics.addBody(block, {density = 1, bounce = 0})
block.bodyType = 'static'
blocks:insert(block)
end
addPlayer()
end
Step 10: Add Player
The player will be added when the initial blocks are in stage. It will appear in the center X of the stage.
function addPlayer()
player = display.newImage('player.png')
player.x = (display.contentWidth * 0.5)
player.y = player.height
physics.addBody(player, {density = 1, friction = 0, bounce = 0})
player.isFixedRotation = true
gameListeners('add')
end
Step 11: Move Player
The Accelerometer is used to move the player across the screen, the value is calculated using the xGravity property.
function movePlayer:accelerometer(e) -- Accelerometer Movement player.x = display.contentCenterX + (display.contentCenterX * (e.xGravity*3))
Step 12: Screen Borders
This code prevents the player from going offscreen on the sides.
-- Borders if((player.x - player.width * 0.5) < 0) then player.x = player.width * 0.5 elseif((player.x + player.width * 0.5) > display.contentWidth) then player.x = display.contentWidth - player.width * 0.5 end end
Step 13: Add Regular Block
This function is called by a Timer. It will calculate a random number between 1 and 4 and when the result equals 1, a bad block will be added. If the result is different than 1, a normal block will be instantiated. The blocks are added to a Table, this way we are able to access them outside this function.
function addBlock()
local r = math.floor(math.random() * 4)
if(r ~= 0) then
local block = display.newImage('block.png')
block.x = math.random() * (display.contentWidth - (block.width * 0.5))
block.y = display.contentHeight + block.height
physics.addBody(block, {density = 1, bounce = 0})
block.bodyType = 'static'
blocks:insert(block)
else
local badBlock = display.newImage('badBlock.png')
badBlock.name = 'bad'
physics.addBody(badBlock, {density = 1, bounce = 0})
badBlock.bodyType = 'static'
badBlock.x = math.random() * (display.contentWidth - (badBlock.width * 0.5))
badBlock.y = display.contentHeight + badBlock.height
blocks:insert(badBlock)
end
end
Step 14: Add Live Graphic
Another timed function, a live graphic will be added when the timer is complete. The live position will be the last block in the table - 1.
function addLive()
live = display.newImage('live.png')
live.name = 'live'
live.x = blocks[blocks.numChildren - 1].x
live.y = blocks[blocks.numChildren - 1].y - live.height
physics.addBody(live, {density = 1, friction = 0, bounce = 0})
end
Step 15: Game Listeners
This function adds and removes the necessary listeners to start the game.
function gameListeners(action)
if(action == 'add') then
Runtime:addEventListener('accelerometer', movePlayer)
Runtime:addEventListener('enterFrame', update)
blockTimer = timer.performWithDelay(800, addBlock, 0)
liveTimer = timer.performWithDelay(8000, addLive, 0)
player:addEventListener('collision', collisionHandler)
else
Runtime:removeEventListener('accelerometer', movePlayer)
Runtime:removeEventListener('enterFrame', update)
timer.cancel(blockTimer)
timer.cancel(liveTimer)
blockTimer = nil
liveTimer = nil
player:removeEventListener('collision', collisionHandler)
end
end
Step 16: Code Review
Here is the full code written in this tutorial alongside with comments to help you identify each part:
-- Blocks 'Rapid Roll' like Game
-- Developed by Carlos Yanez
-- Hide Status Bar
display.setStatusBar(display.HiddenStatusBar)
-- Physics
local physics = require('physics')
physics.start()
physics.setGravity(0, 0)
-- Graphics
-- [Background]
local bg
-- [Title View]
local title
local startB
local creditsB
-- [TitleView Group]
local titleView
-- [CreditsView]
local credits
-- [Score & Lives]
local live
local livesTF
local lives = 3
local scoreTF
local score = 0
local alertScore
-- [Blocks group, Player]
local blocks
local player
--[GameView Group]
local gameView
-- Variables
local moveSpeed = 2
local blockTimer
local liveTimer
-- Functions
local Main = {}
local addTitleView = {}
local initialListeners = {}
local showCredits = {}
local hideCredits = {}
local destroyCredits = {}
local gameView = {}
local addInitialBlocks = {}
local addPlayer = {}
local movePlayer = {}
local addBlock = {}
local addLive = {}
local gameListeners = {}
local update = {}
local collisionHandler = {}
local showAlert = {}
function Main()
addTitleView()
end
function addTitleView()
bg = display.newImage('bg.png')
title = display.newImage('titleBg.png')
startB = display.newImage('startBtn.png')
startB.x = display.contentCenterX
startB.y = display.contentCenterY
startB.name = 'startB'
creditsB = display.newImage('creditsBtn.png')
creditsB.x = display.contentCenterX
creditsB.y = display.contentCenterY + 60
creditsB.name = 'creditsB'
titleView = display.newGroup()
titleView:insert(title)
titleView:insert(startB)
titleView:insert(creditsB)
initialListeners('add')
end
function initialListeners(action)
if(action == 'add') then
startB:addEventListener('tap', gameView)
creditsB:addEventListener('tap', showCredits)
else
startB:removeEventListener('tap', gameView)
creditsB:removeEventListener('tap', showCredits)
end
end
function showCredits()
credits = display.newImage('creditsView.png')
transition.from(credits, {time = 400, x = display.contentWidth * 2, transition = easing.outExpo})
credits:addEventListener('tap', hideCredits)
startB.isVisible = false
creditsB.isVisible = false
end
function hideCredits()
startB.isVisible = true
creditsB.isVisible = true
transition.to(credits, {time = 600, x = display.contentWidth * 2, transition = easing.outExpo, onComplete = destroyCredits})
end
function destroyCredits()
credits:removeEventListener('tap', hideCredits)
display.remove(credits)
credits = nil
end
function gameView()
initialListeners('rmv')
-- Remove MenuView, Start Game
transition.to(titleView, {time = 500, y = -titleView.height, onComplete = function()display.remove(titleView) titleView = nil addInitialBlocks(3)end})
-- Score Text
scoreTF = display.newText('0', 303, 22, system.nativeFont, 12)
scoreTF:setTextColor(68, 68, 68)
-- Lives Text
livesTF = display.newText('x3', 289, 56, system.nativeFont, 12)
livesTF:setTextColor(245, 249, 248)
end
function addInitialBlocks(n)
blocks = display.newGroup()
for i = 1, n do
local block = display.newImage('block.png')
block.x = math.floor(math.random() * (display.contentWidth - block.width))
block.y = (display.contentHeight * 0.5) + math.floor(math.random() * (display.contentHeight * 0.5))
physics.addBody(block, {density = 1, bounce = 0})
block.bodyType = 'static'
blocks:insert(block)
end
addPlayer()
end
function addPlayer()
player = display.newImage('player.png')
player.x = (display.contentWidth * 0.5)
player.y = player.height
physics.addBody(player, {density = 1, friction = 0, bounce = 0})
player.isFixedRotation = true
gameListeners('add')
end
function movePlayer:accelerometer(e)
-- Accelerometer Movement
player.x = display.contentCenterX + (display.contentCenterX * (e.xGravity*3))
-- Borders
if((player.x - player.width * 0.5) < 0) then
player.x = player.width * 0.5
elseif((player.x + player.width * 0.5) > display.contentWidth) then
player.x = display.contentWidth - player.width * 0.5
end
end
function addBlock()
local r = math.floor(math.random() * 4)
if(r ~= 0) then
local block = display.newImage('block.png')
block.x = math.random() * (display.contentWidth - (block.width * 0.5))
block.y = display.contentHeight + block.height
physics.addBody(block, {density = 1, bounce = 0})
block.bodyType = 'static'
blocks:insert(block)
else
local badBlock = display.newImage('badBlock.png')
badBlock.name = 'bad'
physics.addBody(badBlock, {density = 1, bounce = 0})
badBlock.bodyType = 'static'
badBlock.x = math.random() * (display.contentWidth - (badBlock.width * 0.5))
badBlock.y = display.contentHeight + badBlock.height
blocks:insert(badBlock)
end
end
function addLive()
live = display.newImage('live.png')
live.name = 'live'
live.x = blocks[blocks.numChildren - 1].x
live.y = blocks[blocks.numChildren - 1].y - live.height
physics.addBody(live, {density = 1, friction = 0, bounce = 0})
end
function gameListeners(action)
if(action == 'add') then
Runtime:addEventListener('accelerometer', movePlayer)
Runtime:addEventListener('enterFrame', update)
blockTimer = timer.performWithDelay(800, addBlock, 0)
liveTimer = timer.performWithDelay(8000, addLive, 0)
player:addEventListener('collision', collisionHandler)
else
Runtime:removeEventListener('accelerometer', movePlayer)
Runtime:removeEventListener('enterFrame', update)
timer.cancel(blockTimer)
timer.cancel(liveTimer)
blockTimer = nil
liveTimer = nil
player:removeEventListener('collision', collisionHandler)
end
end
Next Time...
In the next and final part of the series, we'll handle the blocks and player movement, collisions, 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