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 .
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Make a Simple Game with Moai
55 mins
- What is Moai?
- Getting Started
- Ready Player One — Getting Your Project Ready
- What’s Invisible and Smells Like Carrots? — Adding Sprites to the Game
- Fast Food — Setting Object Position and Movement
- Cats and Dogs and Bunnies, Oh My! — Adding Characters to the Game
- Feeding the Hordes — Adding Interaction to the Game
- Picky Eaters — Adding Drag and Drop Logic to the Game
- Meow, Bark, Squeak — Adding Sound to your Game
- You’ve Been Fed, Now Shoo! – Removing Sprites
- Won’t These Animals Ever Stop Eating? — Displaying the Score On-Screen
- Taking this Dog and Pony Show On the Road — The Mobile Version
- Where to Go From Here?
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! :]