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!