Corona – Game Loops part 3

Following up on my previous two posts, this discussion will continue with the game loop topic. Here I’ll create a couple game objects, or actor objects, that will work with the game loop.

As previously discussed, actors work need to interface with the game loop by implementing the update(deltaTime) method. This interface is just a function that each actor object must posses. How the actors implement this function is up to the actor.

In this example I’ll create two types of objects. One object will start at the top of the screen and move down the screen. I’ll call these objects rocks.

The second object will move to the location of a touch on the screen. I’ll call this a ship.

Object when created will need to add themselves to the game_loop. To make this easy we’ll use the singleton nature of Lua modules to help. Every file that uses require(“game_loop”) will be getting a reference to the same programming object. Any module that require game loop will be talking to the same game loop.

The rock objects will remove themselves from the display when they reach the bottom of the screen. This means, rocks will also have to remove themselves from the game loop at the time they remove themselves from the display. To make this easy we’ll make use of the singleton nature of the game_loop module again.

rocks.lua –
I made a file named rocks.lua. This file contains the code that will produce “rock” objects. The rocks will fall down the and remove themselves when they get past the bottom edge of the screen.

The rocks module have the following methods.

make() rock – This function returns a rock.

This module requires game_loop.

The rocks module acts as factory that produces rock objects. Each rock is is a Corona shape object, a rectangle. Corona display objects are essentially tables. Each rock has two methods.

rock:remove() – removes the rock from game_loop, and then from display.
rock:update( deltaTime ) – updates the position of the rock.


--------------------------------------------------------------------
--
-- rocks.lua 
-- 
--------------------------------------------------------------------
local M = {}
--------------------------------------------------------------------

local game_loop = require("game_loop")

local xMax = display.contentWidth
local xMin = 0
local yMax = display.contentHeight + 40
local yMin = 0

local function make()
	local rock = display.newRect( 0, 0, 40, 40 )
	rock:setFillColor( 0, 1, 0 )
	rock.x = math.random( xMin, xMax )
	rock.y = yMin - 40
	rock.speed = math.random() * 3 
	
	function rock:remove()
		game_loop.remove( self )
		display.remove( self ) 
	end
	
	function rock:update( dt ) 				-- receive dt here as a parameter. 
		self.y = self.y + self.speed * dt 	-- Use dt, multiply by pixels per frame (speed)
		if self.y > yMax then 
			
			self:remove()
		end 
		return self
	end
	
	game_loop.add( rock )
	 
	return rock
end 
M.make = make

--------------------------------------------------------------------
return M

ship.lua –
The ship.lua module is very similar to the rocks module. This module acts as factory that produces ship objects. The ship module has a single method.

make() ship – The make method returns a a ship object.

The ship module requires the game_loop module. Each ship created is added to game_loop.

Ship objects have three methods.

ship:move_to( x, y ) – starts the ship moving towards the x, and y.
ship:remove() – Removes the ship from game_loop and from the display.
ship:update( deltaTime ) – Updates the position of the ship.


-----------------------------------------------
--
-- ship.lua
-- 
-----------------------------------------------
local M = {}
-----------------------------------------------
local game_loop = require( "game_loop" )
-----------------------------------------------

local function make()
	local ship = display.newRect( display.contentCenterX, display.contentHeight - 100, 20, 40 )
	
	ship.target_x = ship.x
	ship.target_y = ship.y
	
	function ship:move_to( x, y )
		self.target_x = x
		self.target_y = y
	end 
	
	function ship:remove()
		game_loop.remove( self )
		display.remove( self )
	end 
	
	function ship:update( dt )
		ship.x = ship.x - (ship.x - ship.target_x) * 0.1
		ship.y = ship.y - (ship.y - ship.target_y) * 0.1
	end 
	
	game_loop.add( ship )
	
	return ship
end 
M.make = make

-----------------------------------------------
return M 

Here’s a simple program to test out the modules defined above.


-----------------------------------------------------
-- Import the game loop module 
local game_loop = require("game_loop")
game_loop:run()
-----------------------------------------------------

-- Make a player
local ship = require( "ship" ) 
local player = ship.make()

local function move_ship( x, y )
	player:move_to( x, y )
end 

local function on_touch( event )
	if event.phase == "began" then 
		move_ship( event.x, event.y )
	elseif event.phase == "moved" then 
		move_ship( event.x, event.y )
	end
end 
Runtime:addEventListener( "touch", on_touch )
-----------------------------------------------------

-- A function to make rocks
local rocks = require( "rocks" )

local function make_rock()
	local rock = rocks.make()
end 

-- Use a timer to make rocks periodically
local rock_timer = timer.performWithDelay( 900, make_rock, 0 )
-----------------------------------------------------

Let’s take a look at each part. The first two lines load up the game_loop module, and start it running.


local game_loop = require("game_loop")
game_loop:run()

Next we make a player object. The player object will be made from a ship object. To move the ship I’m calling on the ship objects move_to( x, y ) method. Here I made a touch event that calls on move_to() with the event.x and event.y. Which tells the player/ship to move to the position of the touch event.

The event calls move_ship() during both the began and moved phases. The effect is that the ship will start moving to the position of the point your finger makes contact with the screen, and updates position as you drag your finger across the screen.


local ship = require( "ship" ) 
local player = ship.make()

local function move_ship( x, y )
	player:move_to( x, y )
end 

local function on_touch( event )
	if event.phase == "began" then 
		move_ship( event.x, event.y )
	elseif event.phase == "moved" then 
		move_ship( event.x, event.y )
	end
end 
Runtime:addEventListener( "touch", on_touch )

Lest create a timer to create a new rock every 900 milliseconds.


local rocks = require( "rocks" )

local function make_rock()
	local rock = rocks.make()
end 

-- Use a timer to make rocks periodically
local rock_timer = timer.performWithDelay( 900, make_rock, 0 )

Here’s a few ideas to try on your own.

Make a new object type that moves differently from the two examples here.
Add some new features to the one or both of the objects here. For example make the rocks rotate as they move down the screen.
Use images, or better yet sprites, in place of the rectangles I used.

Leave a Reply

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