Corona Coin Drop with Corona SDK Part 2

Hello and welcome back to the game tutorial series for Corona Coin Drop! In Part 2, we will set up our game scene, add some variables, and setup our functions. Let’s get started!

scene-game.lua

Let’s start out by creating a new file titled scene-game.lua and placing it in your project folder. Then, copy and paste the scene template from https://docs.coronalabs.com/api/library/composer/index.html#scene-template to your newly created file.

Once you have the scene setup, we’ll first add in our widgets and start physics. We’ll be using physics for collision detection and the default settings that come with the physics library is more than enough for our game. Place the following code at the top of scene-game.lua. Note: I’ve commented out the last line here. If you’d like to see the collision boundaries of the objects we add, uncomment the line by removing the two dashes.

local composer = require( "composer" )
local scene = composer.newScene()
local widget = require( "widget" )
local physics = require( "physics" )
physics.start()
--physics.setDrawMode("hybrid")

After our libraries have been added, we’ll set some values that we’ll be using later on. The first set of variables are used for positioning while the second set of values are used throughout the game. Lua is self documenting in that the variable names describe what they do. However, I have left comments next to each variable set to better describe what they do.

-- These values are set for easier access later on.
local acw = display.actualContentWidth
local ach = display.actualContentHeight
local cx = display.contentCenterX
local cy = display.contentCenterY
local top = display.screenOriginY
local left = display.screenOriginX
local right = display.viewableContentWidth - left
local bottom = display.viewableContentHeight - display.screenOriginY

local onTilt, dropCoins, onMenuTouch, onGlobalCollision -- forward declares for functions
local tmr_startGame, tmr_dropCoins -- forward declares for our timers
local player, playerScore -- forward declares for our player and player score
local playerScoreCounter = 0 -- a counter to keep track of player points
local coins = {} -- a table to store the coin objects
local coinCounter = 1 -- a counter to track the number of coins
local sensitivity = 2000 -- adjust this value to make the player more slower or quicker
Adding Functionality

The next four parts will be setting up the functions for our game. These functions will be called at certain points in our game and will everything run. We’ll tackle adding graphics to the game in Part 3.

Let’s start our functions by creating a function that will run when the player tilts the device. When the player tilts the device to the left, the event.xGravity will be a negative value and the player will move left. The opposite will happen when the player tilts the phone to the right. We are only change the x axis since we only want our player to move left and right.

-- This function will move the player based on x axis tilt.
onTilt = function(event)
 player:setLinearVelocity( sensitivity * event.xGravity, 0 )
 return true
end

After the tilt function, we’ll create a function that will drop coins from the ‘sky’. The coins will have a physics body attached to it so we know when the coin collides with the player or floor. When the coin collides with the floor, we will subtract one point. On the flip side, one point will be added for each coin caught. Don’t forget, if you need the graphics, they are available for free under Templates.

-- Create the coins that will drop from the sky for the player to catch.
dropCoins = function()
 coins[coinCounter] = display.newImageRect("images/coin.png", 110, 110)
 coins[coinCounter].x = math.random(left, right)
 coins[coinCounter].y = top - 60
 physics.addBody(coins[coinCounter], {radius=55})
 coins[coinCounter].myName = "coins"
 coinCounter = coinCounter + 1
end

We’ll also need a way for the game to stop running so the player can return to the menu. The function onMenuTouch will handle this functionality. When the player wants to return to the menu, we’ll stop the listeners, cancel our timers, remove all coins, and then send the player back to the menu scene.

-- Return the player to the menu and stop the game from running. We'll also run through the coins table to remove all coins.
onMenuTouch = function(event)
 if(event.phase == "began") then
  Runtime:removeEventListener("accelerometer", onTilt )
  Runtime:removeEventListener( "collision", onGlobalCollision )
  timer.cancel(tmr_dropCoins)

  for i=1,coinCounter do
   if(coins[i]) then
    display.remove(coins[i])
   end
  end

  composer.gotoScene("scene-menu", "fade")
 end
end

Collision Detection

The ability to detect collisions within our game is the biggest learning concept for our game. We need to listen for colliding objects between the player and the coin and the coin to the floor. I’ve left comments next to the major portions of our collision function, but let’s review the code.

We start out by storing the colliding objects into a variable that is easily referenced. Then, we create 3 functions that will decrease the score, fade out an object, and increase the score. The object fade will happen when coins collide with the floor.

The function is wrapped up by looking for what object collides with what. When the colliding objects are player/coin, the score will be increased by one and the coin is removed. When the colliding objects are floor/coin, the coin is faded out and the player’s score is decreased by one. Here’s the full code:

-- Our global collision detector to detect colliding objects between player/coin and coin/floor. The player score will then go up or down accordingly.
onGlobalCollision = function(event)

    local obj1 = event.object1 -- store the first object
    local obj2 = event.object2 -- store the second object

    local function decrementScore() -- decrease player score
      playerScoreCounter = playerScoreCounter - 1
      playerScore.text = "Score: "..playerScoreCounter
    end

    local function fadeObject(obj) -- fade the coins out when they hit the floor
      obj.myName = "lostCoin"
      decrementScore()
      transition.to(obj, {alpha = 0, onComplete=function(self) display.remove(self); end})
    end

    local function incrementScore(obj) -- increase the player score
      obj.myName = "grabbedCoin"
      transition.to(obj, {alpha = 0, onComplete=function(self) display.remove(self); end})
      playerScoreCounter = playerScoreCounter + 1
      playerScore.text = "Score: "..playerScoreCounter
    end

    if ( event.phase == "began" ) then
      if(obj1.myName == "coins" and obj2.myName == "floor") then -- listen for coins/floor collision
        timer.performWithDelay(1, function() fadeObject(obj1); end, 1) -- don't ever remove an object in the middle of collision detection. Wait until the collision is over
      end
      if(obj1.myName == "floor" and obj2.myName == "coins") then -- listen for floor/coins collision
        timer.performWithDelay(1, function() fadeObject(obj2); end, 1)
      end

      if(obj1.myName == "player" and obj2.myName == "coins") then -- listen for player/coins collision
        timer.performWithDelay(1, function() incrementScore(obj2); end, 1)
      end
      if(obj1.myName == "coins" and obj2.myName == "player") then -- listen for coins/player collision
        timer.performWithDelay(1, function() incrementScore(obj1); end, 1)
      end
    end
end

Once you review the code once or twice, the collision detection doesn’t seem that scary. We essentially have 4 if/then statements and 3 functions wrapped up into one big one. In the next part of this tutorial, we’ll start adding objects to our game. Stay tuned for part 3!

Leave a Reply

Your email address will not be published. Required fields are marked *