Home Archive Tutorials

How to Make a Simple iOS and Android Game with Corona Tutorial

This is a post by Tutorial Team Member Greg Pugh, author of the Colin Turtle children’s eBook app series. You can also find him on Google+. You have probably seen some stories on the news and on the web about kids that are developing mobile apps at an early age. Often they use the Corona […]


  • Other, Other, Other
Learn how to make a simple iPhone and Android game with the Corona SDK!

Learn how to make a simple iPhone and Android game with the Corona SDK!

This is a post by Tutorial Team Member Greg Pugh, author of the Colin Turtle children’s eBook app series. You can also find him on .

You have probably seen some stories on the news and on the web about kids that are developing mobile apps at an early age. Often they use the Corona SDK to develop these apps.

This is because Corona SDK is really easy to get started with, even if you’re pretty new to programming.

However it’s not just for beginners – advanced developers like Corona too! Here are two big reasons why:

  • Corona is cross-platform. Corona games are cross-platform, so you can write them once and have them work on iOS, Android, and more.
  • Corona allows rapid development. Corona has a high-level language built around rapid development, so you can develop games with it much more quickly than with lower-level frameworks like OpenGL or Cocos2D.

We’ve had other tutorials on Corona on this website in the past, but they have been at a more advanced level, or required third party tools.

So we wanted to make a tutorial for complete beginners showing how to make an extremely simple game with Corona – hence this tutorial was born! :]

In this tutorial, you’ll learn how to get started with Corona and create a simple but fun balloon popping game. The best part is it will run on multiple mobile devices – using the exact same code!

Getting Started

The first thing you’ll need is the Corona SDK, so go ahead and download the SDK.

Note: For this tutorial, you can just use the unlimited free trial version of the SDK. You’ll only need to purchase a license if you decide you want to distribute your app to the various app stores. You can read more about the various Corona license programs here.

Once downloaded, installing the SDK is a fairly straightforward process if you’re on a Mac. Simply open the DMG, accept the software license agreement, and then drag the Corona folder to your Applications folder. That’s it!


If you’re on a Windows machine, however, the installer will probably run you through the installation process step-by-step.

Open the Corona SDK Simulator to make sure that everything works. On a Macintosh, it will likely be located in Applications > CoronaSDK. If this the first time you run the simulator, you will need to accept the terms of the license agreement.

Then you will be prompted to login to your Corona Developer account. If you don’t have one, don’t sweat it! You can take the opportunity now to create one. This is a one-time operation, and you won’t have to do this once you’ve created an account and logged in.

Once logged in, you should see the following screen. Now you’re ready to get started with Corona! :]

Choosing a Text Editor

The next thing you’ll need is a basic text editor. If you’re on a PC, feel free to use Notepad which comes with Windows. If you’re on a Macintosh, you can use TextEdit.

If you’re a Mac developer and you want a more advanced text editor, I recommend you use TextMate instead. This is because it can import auto-completion tags specifically for Corona SDK Lua coding. Also, it allows you to set up your own auto-completion keywords to make code completion a little easier.

Ludicrous Software has graciously supplied free Corona auto-complete tags for TextMate here. If you’re not sure if you want to pay for the software, TextMate comes with a 30 day free trial.

If you want to go REALLY big and work with a full-blown IDE, try CoronaComplete or Lua GLIDER :] Each one has its own advantages and disadvantages, but it’s up to you to pick the tool that would work the best for you.

Being Resourceful

Now that you have the SDK installed and have an editor to write your code, it’s time to get started on your game! But what would a game be without artwork and sound effects?

To save you time, I’ve created some artwork and sound effects for you for this tutorial. So go ahead and download these resources for the tutorial and unzip it to your desktop or folder of choice.

The top-level folder from the resources archive, BalloonPop, will be the project folder for your Corona application – this is where you will be saving your code files.

Feel free to take a peek at the beautiful artwork and cool sound effects inside!

Resources for the project

Building Our Settings

All Corona applications have a main.lua file, which is the starting point for the application. But in addition, a Corona application needs a few other files such as build.settings and config.lua, which define the application parameters.

So let’s start by creating the settings and config files! :]

Start your text editor, create a new file and save it as build.settings in the BalloonPop folder. Make sure that the extension for the new file is .settings and not .txt.

Copy and paste the following code into build.settings, then save and close the file:

settings = {
        orientation = {
                default = "landscapeRight",
                supported = {

This instructs the application to use “landscape right” orientation.

Configuring Your Config File

Create another new file in your text editor and save it in the BalloonPop folder as config.lua.

Copy and paste the following code to config.lua, save and close.

application = {
	content = {
		fps = 60,
		width = 320,
		height = 480,
		scale = "zoomStretch",
		imageSuffix = {
			["@2x"] = 2;

The code above tells the application to run at 60 frames per second, to have a default size of 320 x 480 (the iPhone screen resolution) to stretch the graphics when displayed on different resolutions, and to display @2x retina graphics where applicable.

If you’re not comfortable with your graphics stretching to fit different resolutions, you can substitute “letterbox” instead of “zoomStretch” in the above code.

And that’s all the setup parameters required for this app! Easy, wasn’t it? :] These parameters will ensure that your app looks the same on all devices.

Onto the Main Event

Now create another file in your text editor and save it as main.lua in the BalloonPop folder.

Start the Applications\Corona SDK\Corona SDK Simulator, and then navigate to File > Open. Browse to the BalloonPop folder, and open the main.lua file you just created.

Navigate to “Window > View As” in the Corona SDK Simulator menu to view your application running on different devices. For now, use the iPhone simulator.

At this point, you should be seeing a black screen! How exciting! You’re obviously thinking “What gives? I created three code files for this?!” Patience, grasshopper, there’s more going on in the simulator than meets the eye! :]

When main.lua was opened, the simulator ran the app in landscape mode, based on the configuration setting you created in build.settings. The simulator is also displaying a 320×480 screen at 60 frames per second – again as per the settings in config.lua.

The only problem is that there’s just nothing to display yet! :] Time for you to put something up on the screen as a reward for all of the work you’ve done so far!

Open main.lua in your text editor and paste in the following:

local background = display.newImage("images/clouds.png");

The code above creates a local variable (hence the “local” keyword) named background and assigns a new image to display. “display” in this case refers to the device screen. In Corona, the display object has many methods, such as “newImage” which can be used to add elements to be displayed on screen.

Save your changes. The Corona simulator should automatically detect the changes and prompt you to relaunch the simulator. When you do, you’ll see your new background image in all of its glory!

Note: One thing to remember is that semicolons are not necessary at the end of a line in Lua coding. Many programmers tend to use them anyway since they’re commonplace in many other coding languages, but if you forget them, it won’t have any effect on your application.

Care to Comment?

As you continue adding more code to your Corona project, you’ll want to comment various sections so that you can remember what you did later!

To add comments in Lua, use double dashes for single line comments. For block comments, use –[[ Comment here –]]. You’ll be using comments a lot in this tutorial so that you’ll know exactly what each piece of code does.

To get a feel for comments, change your first line of code to read:

-- Display a background image
--[[ Here we are inserting
a background image of clouds --]]
local background = display.newImage("images/clouds.png");

The code above shows both a single line comment (the first line) and a multi-line block comment (the second and third lines). A multi-line comment can continue over several lines, and the comment will continue until you hit the comment-end marker, which is –]].

Status Bar? We Don’t Need No Steenkin’ Status Bar!

The background image shows up nicely. However, on iOS devices, you’re stuck with the status bar covering part of our image!

Hide the status bar by adding the following code to the beginning of main.lua:

-- Hide status bar

When you re-launch the simulator, the status bar is now hidden.

Let’s Get Down with Physics

So in just two lines of code, you have a background image displayed, and the status bar hidden. Not too bad at all! :]

Now it’s time to add in a complex physics system so your game will support gravity and physics simulations. Sound like a scary proposition?

Actually, you can do this with one line of code! Add the following to the end of main.lua:

local physics = require("physics");

And that’s it! Add in a comment line above the line you just added for good measure:

-- Generate Physics Engine
local physics = require("physics");

Constantly Writing Variables

As you’ve seen so far, Lua coding is pretty straightforward. Time to kick it up a notch! :]

Add the following code to the end of main.lua:

-- 1. Enable drawing mode for testing, you can use "normal", "debug" or "hybrid"

-- 2. Enable multitouch so more than 1 balloon can be touched at a time

-- 3. Find device display height and width
_H = display.contentHeight;
_W = display.contentWidth;

-- 4. Number of balloons variable
balloons = 0;

-- 5. How many balloons do we start with?
numBalloons = 100;

-- 6. Game time in seconds that we'll count down
startTime = 20;

-- 7. Total amount of time
totalTime = 20;

-- 8. Is there any time left?
timeLeft = true;

-- 9. Ready to play?
playerReady = false;

-- 10. Generate math equation for randomization
Random = math.random;

-- 11. Load background music
local music = audio.loadStream("sounds/music.mp3");

-- 12. Load balloon pop sound effect
local balloonPop = audio.loadSound("sounds/balloonPop.mp3");

Note: Be sure to save your changes to main.lua after each edit – just in case!

Each commented line in the above code briefly explains what each line does, but here’s a more detailed explanation of the changes above, one-by-one:

  1. This will make more sense when you apply physics to the balloons; for now leave the draw mode set to “normal”.
  2. This enables the detection of multiple touches at once, letting the user pop more than one balloon at a time in your game. However, the Corona Simulator currently does not support multitouch. So you’ll only be able to test multitouch on an actual device.
  3. These are constant values you’ll use to keep track of the device’s screen width and height. As every device will vary in size, it is easier to place objects on screen using relative placement versus absolute.
  4. This keeps track of the current number of balloons. You will start with 0 balloons and generate more balloons as the game loads.
  5. When the game is fully loaded, the game will start with 100 balloons that the user has to pop in an allotted amount of time.
  6. This is the amount of time that the player will have to pop as many balloons as possible. This will be the countdown time.
  7. Since the startTime will be constantly counting down each second, you will keep track of how much total time the player had to begin with.
  8. The player will start with time remaining on the countdown time, so this variable is true when there is time left. If the countdown reaches 0, the variable will be set to false.
  9. The game is not ready to play if the balloons are still loading, so this is initially set to false. When the balloons are finished loading, you set playerReady equal to true.
  10. You want the balloons to generate randomly along the x-axis, so you need a way to generate random values. Set up a pointer to the random function of the math library and name it “Random”.
  11. When the app starts you will need to load the music avoid sound lagging. The variable “music” will load a background music track included in the source files.
  12. A game is no fun without sound effects! So you load a sound effect here to play when the balloons are popped.

Giving the Player Feedback

When you save your changes to main.lua, nothing new will happen in the simulator since the code simply sets up the variables above. Time to create some text to give the player feedback!

Add the following code below the variable section in main.lua:

-- Create a new text field using native device font
local screenText = display.newText("...Loading Balloons...", 0, 0, native.systemFont, 16*2);
screenText.xScale = 0.5
screenText.yScale = 0.5;

-- Change the center point to bottom left

-- Place the text on screen
screenText.x = _W / 2 - 210;
screenText.y = _H - 20;

In the code above, you create a variable named screenText and assign it a line of text to display in the device’s native font. Then you set the text to scale evenly, regardless of the device.

The reference point is at the bottom left hand corner of the object in question, relative to the coordinates that are used for that particular object. In this case, when you specify coordinates for the screenText item, the bottom left of the item is placed at the specified coordinate point.

For the x coordinate placement, you take the width of the screen, divide it in half and then move the text over 210 pixels to the left. For the y coordinate, you take the height of the screen and move up 20 pixels up from the bottom.

Note: Corona coordinates start with 0,0 being the top left corner of the screen.

Refresh the simulator (if you haven’t been prompted to do so already) and you should see the following:

Navigate to “Window > View As” in the simulator and change devices. The loading text should stay in approximately the same place for every device, and the app should look very similar regardless of the device selected.

Change back to the iPhone view and add some code to main.lua to show the player the countdown (all code gets added below the previous code in the file, unless unless otherwise stated):

-- Create a new text field to display the timer
local timeText = display.newText("Time: "..startTime, 0, 0, native.systemFont, 16*2);
timeText.xScale = 0.5
timeText.yScale = 0.5;
timeText.x = _W / 2;
timeText.y = _H - 20;

This is exactly the same as the screenText variable, except that now you display the value of the startTime variable in place of hardcoded text. And of course, the text is placed at a different x coordinate, otherwise it would overlap the existing loading text.

Save your main.lua file changes and the simulator should refresh:

Bring Balloons to the Party

So far everything is going smoothly, but it’s not a very good game yet! Let’s add some gravity and balloons to spice things up a bit:

-- 1. Start the physics engine

-- 2. Set gravity to be inverted
physics.setGravity(0, -0.4)	

local function startGame()
	-- 3. Create a balloon, 25 pixels by 25 pixels
	local myBalloon = display.newImageRect("images/balloon.png", 25, 25);
	-- 4. Set the reference point to the center of the image
	-- 5. Generate balloons randomly on the X-coordinate
	myBalloon.x = Random(50, _W-50);
	-- 6. Generate balloons 10 pixels off screen on the Y-Coordinate
	myBalloon.y = (_H+10);
	-- 7. Apply physics engine to the balloons, set density, friction, bounce and radius
	physics.addBody(myBalloon, "dynamic", {density=0.1, friction=0.0, bounce=0.9, radius=10});

-- 8. Create a timer for the game at 20 milliseconds, spawn balloons up to the number we set numBalloons
gameTimer = timer.performWithDelay(20, startGame, numBalloons);

The above code adds a function. Functions in Lua are similar to methods in Objective-C. A function can be called from your main code, and you can define a function at any place in your code. But you must first define the function before you can call it — so any code that calls the function must appear after the function itself! Makes sense, doesn’t it? :]

The code then starts the physics engine, creates a new function called startGame which creates floating balloons, and sets up a timer to spawn the balloons on screen.

In just a moment you’ll get a bit more explanation of the code. But at this point, save your work and relaunch the simulator to illustrate what we’ll be talking about.

So now there’s a bunch of balloons floating off the screen! What just happened? Take a look at the code line-by-line:

  1. Get the ball rolling by telling the physics engine to start running.
  2. Set the horizontal gravity at 0 and the vertical gravity at -0.4. The negative gravity values means that vertical gravity, instead of being applied downwards, is applied upwards. So your balloons will rise and not fall.
  3. Create a new variable named myBalloon and assign a 25×25 pixel balloon image to it that is found in the images folder.
  4. Set the reference point for each balloon to be the centre of the object. All positioning for balloons will be relative to the centre of the balloon.
  5. Set the x coordinate for the balloon to a random value between 50 and the screen width minus 50 pixels. Each balloon is placed randomly in the space 50 pixels in from both edges of the screen.
  6. Set the balloon’s starting point 10 pixels below the bottom screen edge.
  7. Apply dynamic (moving) physics to the balloon and assign the physics properties of friction, amount of bounce, and the radius.
  8. Create a variable named gameTimer, which after 20 milliseconds, calls the startGame function until the numBalloons variable is reached. In this case, numBalloons is 100, so there will be 100 balloons generated.

You may be wondering why a radius value of 10 was chosen for your balloons. This is where physics.setDrawMode(“normal”) comes into play. Change “normal” to “hybrid” in main.lua and then save.Relaunch the simulator when prompted and you should see the following:

Now there is a semi-transparent overlay for anything with physics applied to it, including a 10 pixel circle which completely covers the balloon. If you were to change the radius to 50 and save the file, you would see 50-pixel circles bouncing off of each other.

You can also switch “hybrid” to “debug” to get rid of the artwork and just see physics shapes, as seen below:

The physics drawing modes are handy if you want to make sure that the physics simulation is working correctly, and that physics shapes are being added correctly to the desired objects. Since you know everything is working fine, switch the drawing mode back to “normal”.

Two Walls and a Ceiling

Currently, when the game starts, the balloons all move up, up, up … and away, never to return! It’s going to be a bit difficult trying to pop balloons that don’t stay around for too long!

Create some boundaries to keep the balloons on the screen. Place the following code after the physics.setGravity line but before the startGame function:

--[[ Create "walls" on the left, right and ceiling to keep balloon on screen
	display.newRect(x coordinate, y coordinate, x thickness, y thickness)
	So the walls will be 1 pixel thick and as tall as the stage
	The ceiling will be 1 pixel thick and as wide as the stage 
local leftWall = display.newRect (0, 0, 1, display.contentHeight);
local rightWall = display.newRect (display.contentWidth, 0, 1, display.contentHeight);
local ceiling = display.newRect (0, 0, display.contentWidth, 1);

-- Add physics to the walls. They will not move so they will be "static"
physics.addBody (leftWall, "static",  { bounce = 0.1 } );
physics.addBody (rightWall, "static", { bounce = 0.1 } );
physics.addBody (ceiling, "static",   { bounce = 0.1 } );

As the comment code above tells you, you created 1-pixel thick walls around the screen, and applied physics shapes to the walls so the balloon objects will know to interact with them.

Now if you relaunch the game, you will see that your balloons don’t run away any more! :]

Let’s Play Ball(oon)!

Now that you’ve got everything displaying nicely on the screen, it’s time to think about the gameplay.

You want the user to pop as many balloons as they can by tapping them before the time expires. Depending on how many balloons they’re able to pop, you want different feedback to be displayed. So let’s do that now!

Place the following code before the physics.start() line in main.lua:

local gameTimer;

-- Did the player win or lose the game?
local function gameOver(condition)
	-- If the player pops all of the balloons they win
	if (condition == "winner") then
		screenText.text = "Amazing!";
	-- If the player pops 70 or more balloons they did okay
	elseif (condition == "notbad") then
		screenText.text = "Not too shabby."
	-- If the player pops less than 70 balloons they didn't do so well
	elseif (condition == "loser") then
		screenText.text = "You can do better.";

-- Remove balloons when touched and free up the memory they once used
local function removeBalloons(obj)
	-- Subtract a balloon for each pop
	balloons = balloons - 1;
	-- If time isn't up then play the game
	if (timeLeft ~= false) then
		-- If all balloons were popped
		if (balloons == 0) then
		elseif (balloons <= 30) then
		elseif (balloons >=31) then

If you’re wondering about the local gameTimer declaration, that’s just to ensure that the gameTimer variable (which is set up at the end of the code, after startGame) is already present so that removeBalloons can see it since removeBalloons also refers to the gameTimer variable.

The gameOver function listens for a condition variable indicating how well the player did and displays some text based on the player’s performance.

The removeBalloons function deletes balloons as they are popped and adds each popped balloon to the score.

Since the above code just sets up the game logic, when you save your main.lua file you won’t see any changes in the simulator. These functions may look a little complex, but all they’re doing is checking to see if a user popped a balloon.

If the user pops every balloon before the time expires, the timer countdown is paused and gives the user the message “Amazing!”. If the user pops 70 or more balloons by the time the countdown reaches 0, they’ll receive the message “Not too shabby.”, and if they pop fewer than 70 by the end of the game, they will see “You can do better.”

An important piece of code that you should note is obj:removeSelf() which removes the popped balloons from memory. The removeSelf command removes a display object from screen and releases the memory used by it, as long as there are no other references to that object.

It’s the Final Countdown

You have functions to display a game over message, but where do you start the timer countdown which shows the user how much time is left? Add a countDown function that will start the background music when the game is ready to be played, and counts down the time once the game is loaded.

Place the following code right after removeBalloons:

local function countDown(e)
	-- When the game loads, the player is ready to play
	if (startTime == totalTime) then
		-- Loop background music
		audio.play(music, {loops =- 1});
		playerReady = true;
		screenText.text = "Hurry!"
	-- Subtract a second from start time
	startTime = startTime - 1;
	timeText.text = "Time: "..startTime;
	-- If remaining time is 0, then timeLeft is false 
	if (startTime == 0) then
		timeLeft = false;

It’s worth noting that none of these functions are being called yet – you’re just setting them up. So you still won’t see any changes in the simulator just yet!

Speaking of the startGame function, head back there and set up touch detection for each balloon so that the player can pop them by tapping on them.

In startGame, after the physics.addBody(myBalloon,… line, add the following:

    -- Allow the user to touch the balloons
	function myBalloon:touch(e)
		-- If time isn't up then play the game
		if (timeLeft ~= false) then
			-- If the player is ready to play, then allow the balloons to be popped
			if (playerReady == true) then
				if (e.phase == "ended") then
					-- Play pop sound
					-- Remove the balloons from screen and memory
	-- Increment the balloons variable by 1 for each balloon created
	balloons = balloons + 1;
	-- Add event listener to balloon
	myBalloon:addEventListener("touch", myBalloon);

Note that the above code is adding a function within an existing function, startGame. This may seem strange, but it’s perfectly legal! :]

The code above first increases the balloon count for each balloon (since startGame is called multiple times to create the 100 balloons), and it also sets up each balloon to detect touches and to call the myBalloon function when a touch is detected.

The rest is handled by the myBalloon function. It first checks to see if there’s time left on the clock. If the time has run out, then the player should not be able to pop balloons. And if the player is able to pop balloons, it simply plays a pop noise and calls removeBalloons to handle the rest.

Why Won’t These Balloons Pop?!

So you’ve added the ability to pop the balloons, but what gives? The balloons still won’t pop!

Take a look back at the code for clues. You added the functionality to myBalloon that listens for a user touch. If the balloon is touched, it plays a pop sound and removes the balloon from the app. If there’s time on the clock, the game is allowed to start, and the code tracks each balloon by adding 1 to each generated balloon.

Hey, wait a minute! You never told the game to actually start — d’oh! :]

Add the following code to the end of startGame (just after the spot where the event listener is added to the balloon):

    -- If all balloons are present, start timer for totalTime (10 sec)
	if (balloons == numBalloons) then
		gameTimer = timer.performWithDelay(1000, countDown, totalTime);
		-- Make sure timer won't start until all balloons are loaded
		playerReady = false;

The above code checks if all of the balloons are generated, and if they are, calls the countDown function. Note that the gameTimer variable is re-used here to create a new timer which tracks the time left in the game at 1 second (1000 milliseconds) intervals.

If you run the game now, you will see “…Loading Balloons…” while the balloons are being generated, and then “Hurry!” once the timer starts. You don’t want the player having an unfair advantage and being able to pop balloons before the timer starts. That’s why you have a loading period.

If you want to make the game harder (or easier), altering the game is very easy. You can change the number of balloons or the time by changing the following variables:

-- How many balloons do we start with?
numBalloons = 100;

-- Game time in seconds that we'll count down
startTime = 20;

-- Total amount of time
totalTime = 20;

And there you have it, a balloon game that will run on any device the Corona SDK supports!

Where to Go From Here?

Here is the completed source code for the tutorial.

There’s a lot more you can do to make this game more exciting:

  • Add a counter for the number of balloons popped. This gives the player an idea of their progress in the game; you could even show a total balloons counter which gradually decreases as the player pops more balloons.
  • Add a scoring system where each balloon popped adds to the players score. You can get fancy and have different scores for multiple pops at the same time (you’ll need to figure out how to detect multiple touches first!).
  • Try adding different colored balloons where each colour has a different value, so that popping certain colors (or the same colour in sequence) gives a higher score.
  • Add a reset button so the user can abort the game in progress and start a new one..

In addition, if you want to learn more about Corona, we have two more tutorials about Corona on this site that you might enjoy:

I hope to see you create some fun Corona games in the future! And if you have any questions or comments about this tutorial or Corona in general, please join the forum discussion below!

This is a post by Tutorial Team Member Greg Pugh, author of the Colin Turtle children’s eBook app series. You can also find him on .



More like this