How To Make a Simple Game with Moai

This is a tutorial for beginner Moak SDK developers, you’ll learn how to create a new animal-feeding game for iOS from scratch. With Moai, you don’t need to fear being locked in to one platform — you can let everyone enjoy the fruits of your labors! By .

Leave a rating/review
Save for later
Share
You are currently viewing page 5 of 7 of this article. Click here to view the first page.

Picky Eaters — Adding Drag and Drop Logic to the Game

Being able to drag the food across the screen is a huge milestone in your game. All you need now is a way to know that the food object was released above an animal, and check if it’s the correct kind of food. You won’t earn anything for feeding a rabbit a can of cat food — except probably a dirty look from the rabbit! :]

Add the following code just before spawnFoodObject() in main.lua:

local function foodReleasedAfterDrag ( event )
	local foodObject = event.target
	-- we don't want further interactions with this foodObject
	foodObject.onTouchDown = nil
	foodObject.onTouchUp = nil
	foodObject.isDragable = false

	-- check if it's colliding with either customer or his plate
	-- and if this customer requested that food
	successfulFood = nil
	for custIdx, cust in pairs ( listOfCustomers ) do
		if cust:inside ( event.x, event.y, 0 ) or cust.plate:inside ( event.x, event.y, 0 ) then
			for foodIdx, food in pairs ( cust.requestedFood ) do
				if food.filename == event.target.filename then
					-- it's this customer
					print ( "Customer fed!" )
					successfulFood = food
					layer:removeProp ( food )
					table.remove ( cust.requestedFood, foodIdx )
					if #cust.requestedFood == 0 then
						-- all food is delivered
						print ( "Customer is full!" )
					end
					break
				end
			end
		end
	end

	-- no matter what, food should disappear
	local fadeOut = foodObject:seekColor(0, 0, 0, 0, 1, MOAIEaseType.LINEAR)
	fadeOut:setListener ( MOAIAction.EVENT_STOP, 
		function ()
			layer:removeProp(foodObject)
			foodObject = nil
		end 
	)
end

Once a food item is dragged somewhere, isDragable is set to false which freezes it in place. The function then loops through every customer to check if the food was dropped on the customer or its plate; if the food is something the customer wants, you’ll see a “Customer fed!” message in the terminal. If the customer gets both food items that they wanted, you’ll see a “Customer is full!” message.

Whether or not the food was what the customer wanted, once the food sprite is dropped it will fade out and disappear.

foodReleasedAfterDrag() also uses the listOfCustomers array, which is defined elsewhere in the file. Find the declaration for the array in main.lua – it should look like this:

local listOfCustomers = {}

And move it to the top of the file.

Note: It’s generally a good idea to keep all the local variables that are in the scope of whole file or module at the top of that file. It ensures that you won’t define it in some place, then try to use it some earlier point in the code. This can easily lead to errors – most of them will be trivial to find and fix, but some may be much harder to track down!

Note: It’s generally a good idea to keep all the local variables that are in the scope of whole file or module at the top of that file. It ensures that you won’t define it in some place, then try to use it some earlier point in the code. This can easily lead to errors – most of them will be trivial to find and fix, but some may be much harder to track down!

Next, foodReleasedAfterDrag() needs to be called when the object is dragged and the mouse button is released, or the user’s finger is lifted up.

Paste the following code at the bottom of the spawnFoodObject function, just above the closing “end” statement:

	foodObject.onTouchUp = function ( event )
		foodReleasedAfterDrag ( event )
	end

Run your game and try to feed the animals! You should see the “Customer fed!” message show up in the console if you give the correct food to the correct animal, as in the screenshot below:

Now there’s only a few more pieces to implement. When customers get both of the food items they want, they should disappear, the other customers should be rearranged, and it would be nice if each customer barked, squeaked, or meowed their thanks for being fed! :]

Meow, Bark, Squeak — Adding Sound to your Game

First of all, there are two ways you can play sound in Moai.

The first method is Untz system, which is the one you’ll use in this tutorial. It runs well on the Mac, as well as on iOS and Android devices. The other way is to use FMOD toolkit – if you want to target native Chrome client and use sound in your app, have a look at this.

FMOD does require a license for commercial use; however, it can be used free of charge for non-commercial products.

As usual, the lower-level usage will be wrapped into a single function. Paste the following code near the top of main.lua, right before the “Textures and sprites creation” section:

----------------------------------------------------------------
-- audio play code
----------------------------------------------------------------
-- initialize audio system
MOAIUntzSystem.initialize()
local soundCache = {}
local function playAudio ( filename, volume, isLoop, callbackFunction )
	function threadFunc ()
		if soundCache [ filename ] == nil then
			local sound = MOAIUntzSound.new ()
			sound:load ( filename )
			soundCache [ filename ] = sound
			sound = nil
		end
		local sound = soundCache [ filename ]
		sound:setVolume ( volume )
		sound:setLooping ( isLoop )
		sound:play ()
		if callbackFunction ~= nil then
			-- this allows to wait until execution is done and after that
			-- call the callbackFunction () 
			while sound:isPlaying () do 
				coroutine:yield () 
			end
			callbackFunction ()
		end
	end
	thread = MOAICoroutine.new ()
	thread:run ( threadFunc )
end

Here you can see another implementation of a simple cache for loading and playing sounds similar to the texture cache for sprites.

playAudio() accepts a filename as an argument, and either loads the sound file from disk or from the cache. volume controls the volume level, and isLoop sets whether the sound should loop — or just play once.

callbackFunction is interesting – if you pass a callback function as an argument to playAudio() it will be called once the sound has finished playing. Pretty handy!

Note that the sound playback will happen on its own thread. You don’t want the sound playback to stop the game action, so running the playback on a thread means the audio tasks will happen in the background.

With playAudio() in place, playing a sound is easier than saying “Meow”! :]

Find foodReleasedAfterDrag() in main.lua and locate the “Customer is full!” print statement. Add the following lines so the code looks like this:

	-- all food is delivered
	print ( "Customer is full!" )

	-- Add these following lines:
	-- make a sound
	playAudio ( "audio/" .. cust.soundName, 1, false, function ( )				
	end )

Run your game! Play through, and you’ll note that once a customer gets their two food items, you should be greeted by some friendly animal noises giving you thanks for running such a wonderful snack bar! :]