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