Build a game for iOS and Android with Corona

This article first appeared in issue 223 of .net magazine – the world's best-selling magazine for web designers and developers.

Taking a look at some of today’s top mobile games, it’s easy to see that physics-based games are more popular than ever. And as it turns out, Corona SDK happens to be the perfect tool for producing these hits, as games such as Bubble Ball and Blast Monkeys have already demonstrated, earning the top spot in the iTunes App Store and Android Marketplace in 2011.

Corona SDK features high-performance graphics and includes Box2D physics built-in, which is why it’s perfect for creating these incredibly popular physicsbased titles, or any 2D game for that matter. Corona is hands-down the easiest, fastest way to produce high-quality games and apps for both iOS and Android mobile platforms. In this tutorial, we’ll explore just how it works by walking you through the creation of a simple 2D physics-based game.

Be sure to download all of the tutorial files and look at the source code as we go, because not all of it will be shown here. We’ve got quite a bit of ground to cover, but at the end of it all, you’ll likely be surprised at how fast we were able to create the beginnings of what could be the next mobile hit!

Getting started

Before we continue, you’ll need to create a free Corona Developer account and download the SDK (compatible with both Windows and Mac). Once you have it downloaded, I recommend taking a look at the Quick-Start Guide to familiarise yourself with Corona basics, and to get your development environment set up as well.

Dino Bounce is a fun, 2D physics-based game that has gameplay reminiscent of some best-selling App Store hits

Dino Bounce is a fun, 2D physics-based game that has gameplay reminiscent of some best-selling App Store hits

Once you finish getting things set up, let’s dive right into the main concept of our game. Here’s a brief description of how it’ll work: the game starts with a character, platform and goal on the screen, with the physics simulation paused. The player then drags and positions the platform to the location and rotation of their choice and presses the play button to start the physics simulation. If the platform is positioned correctly, the character will drop, roll, and finally reach the goal (level complete). If the player is unsuccessful (character doesn’t reach the goal), the player must try again. Stars are optionally collected for a higher score.

In this game, there will be very few objects we’ll be working with to include: a background, the character, one platform, a goal, some stars, the ground and two buttons (stop and play). Now that we’ve got all the prep work out of the way, let’s start putting it all together.

Creating a project

With Corona, you can use the same project (code, images, and so on) and build for either iOS or Android platforms at the click of a button

With Corona, you can use the same project (code, images, and so on) and build for either iOS or Android platforms at the click of a button

The only thing that’s needed in a Corona project is a folder with a single text file within it (main.lua). If you’ve taken a look at the source code for our project, however, you’ll notice that – apart from the images folder – there are two other files aside from main.lua: config.lua and build.settings. These two files are only necessary if you want to deviate from the default settings when it comes to things such as orientation, content scaling, and so on.

For a more in-depth explanation of config.lua and build.settings, please see the Configuration Options documentation.

For this project, we’re going to be targeting the iPhone (320x480 resolution) in landscape orientation. However, we’ll also want to take advantage of newer iPhones’ super-sharp 640x960 displays (and similarly sharp Android screens), which is why – in case you haven’t already noticed – there are duplicate assets in the images folder, with one being double the size with an @2x suffix (specified in config.lua).

Setting the stage

When you open up the main.lua module from the source files, you can immediately see that this is where all of the code for our game will go. Lines 14-35 are external libraries (such as widget, line 17, and physics, line 20), some initial settings, and local variables that will be used throughout our game. For our first object, we’ll begin by creating the sky, which will serve as the game’s background (lines 38-40).

local bg = display.newImageRect( "images/background.jpg", 480, 320 )bg:setReferencePoint( display.TopLeftReferencePoint )bg.x, bg.y = 0, 0

Thanks to Corona’s straightforward API, you can probably tell what’s going on just by reading the code, but I’ll walk you through it anyway. The first line will create a new display object from an image (background.jpg), which is 480x320 (pixels) in size. The second line sets the reference point of the object (the point at which an object is positioned and rotated) to the top-left.

Ghosts Vs Monsters is a full-featured, open-source Angry Birds clone made in just 36 hours with the Corona SDK

Ghosts Vs Monsters is a full-featured, open-source Angry Birds clone made in just 36 hours with the Corona SDK

Finally, we do the actual positioning on the last line by changing the object’s x and y properties.

Next, let’s create a flag (goal), the ground, a platform and the character objects in the same manner:

local flag = display.newImageRect( "images/flag.png", 50, 102 )flag.x, flag.y = 420, 200local ground = display.newImageRect( "images/ground.png", 292, 110 )ground:setReferencePoint( display.BottomRightReferencePoint )ground.x, ground.y = display.contentWidth, display.contentHeightlocal platform = display.newImageRect( "images/platform.png", 160, 24 )platform.x, platform.y = 260, 75character = display.newImageRect( "images/critter.png", 80, 80 )character.x, character.y = 75, 80

You may have noticed that the character creation doesn’t begin with local like the rest of the objects. This is due to the fact that we have already declared it as local on line 35 so that other functions (above our character creation code) can access the object without problems. This is known as a forward declaration in Lua.

Another new thing you might notice is the use of display.contentWidth and display.contentHeight. These are simply the current width and height of the screen (as specified in config.lua, or the default device width/height if not specified in config.lua), with the device’s orientation taken into account.

If you were to load the project in the Corona Simulator at this point, you’ll see our project is already starting to come together – pretty easy so far, right? You should see our character in the air, a platform, the ground and the goal, all placed on the sky background.

Adding physics

Now that we have all of our objects in place, we need to add physics to them. At the top of main.lua, you’ll notice we’ve already prepared the physics library for use under the physics namespace (main.lua, line 20).

By default, no objects will react to the ‘physical’ simulation when it’s started. In order for any of our objects to exist in the physical ‘world’ in a Corona app, we need to give them a body.

This is done with the physics.addBody() function. Let’s begin by adding a physical body to the flag object, to give you an idea of how it is accomplished (main.lua, line 47):

physics.addBody( flag, "static", { isSensor=true } )

The line above will add a body to our flag object. The second argument specifies the type of body (dynamic, static or kinematic) that our object has. Since the flag is a fixed object, we’ll set it to static. The isSensor property enables other objects to pass through the flag, but it will still receive collision events so we can detect when something touches it. In short, this will make the flag behave like a non-physical object, but still allow us to detect when the character reaches the goal.

Next, I’ll go over adding a body to the character, since it’s not a fixed object (main.lua, line 136).

physics.addBody( character, { friction=0.3, bounce=0.5, radius=30 } )

Since the default body type in Corona is dynamic, we don’t need to specify it in this call to physics.addBody(). Moving on to the properties table that’s now passed as the second argument, the friction property determines a body’s behaviour when moving along another physical object (such as the ground). The bounce property determines the ‘bounciness’ of an object when it comes into contact with another physical object. Lastly, the radius property ensures this will be a circular body, and corresponds to the object’s on-screen pixel-radius.

Now that you understand how to add physical bodies to display objects, the rest of the body-creation code in main.lua should be easy to understand. For a more in-depth explanation of physics bodies in Corona, see the Physics Bodies documentation.

Ansca mobile is a one-stop resource for Corona users to interact with other developers via the forums, reference APIs and even share code with others

Ansca mobile is a one-stop resource for Corona users to interact with other developers via the forums, reference APIs and even share code with others

Touches and event listeners

Corona utilises what’s known as event-driven programming. Events occur based on countless different factors, but are commonly a result of user input. With our target platform being iOS and Android touch-based mobile devices, the user touching the screen corresponds to a touch event. Corona allows you to listen to these events on a per-object basis and then react accordingly.

Since the entirety of our gameplay consists of the player dragging a platform into the proper location, we need to assign a touch “event listener” to our platform object. An event listener is simply a function that’s executed whenever a specific event is detected.

Here’s what our touch listener for our platform object looks like (main.lua, line 89):

function platform:touch( event ) if not isPlaying then if event.phase == "began" then -- finger just touched display.getCurrentStage():setFocus( self ) self.isFocus = true self.markX, self.markY = self.x, self.yelseif self.isFocus then local moveX = math.abs( event.x - event.xStart ) local moveY = math.abs( event.y - event.yStart ) local moveThresh = 10 if event.phase == "moved" then -- finger "drags" object -- drag object self.x = event.x - event.xStart + self.markX self.y = event.y - event.yStart + self.markY elseif event.phase == "ended" then -- finger is released -- rotate object if not dragged past threshold if moveX < moveThresh or moveY < moveThresh then self.rotation = self.rotation + 10 end -- allow touches to other display objects display.getCurrentStage():setFocus( nil ) self.isFocus = false end end end return trueendplatform:addEventListener( "touch", platform )

At the start of the touch (the began phase), we place the app’s focus on this object and also mark its current location. When the object is dragged, we change its location as the player’s finger moves. Once the player’s finger is lifted, we determine whether the object is dragged past the rotation threshold and make the object react accordingly. The last line assigns the listener to the platform object, and from that point on it will “listen” for player touches.

Looking at your game in Debug or Hybrid physics mode enables you to see exactly how bodies are drawn to help you make necessary adjustments

Looking at your game in Debug or Hybrid physics mode enables you to see exactly how bodies are drawn to help you make necessary adjustments

Adding the final touches

Now we need to add a collision listener to the flag object to detect when the player’s character touches it (main.lua, line 50). Collision listeners behave similarly to touch listeners, but instead occur when two physical objects collide.

In our game, we will notify the user that the level is complete and restart the game when the character object collides with the flag. For more in-depth information on collision listeners, please see the Collision Detection documentation.

While we’re at it, let’s add a star to the level to allow the player to earn extra points whenever the character collects it. To do this we simply create and position the star object, add a body to it, and a collision listener that will remove the star and increase the player’s score upon colliding with the character.

Lastly, we need to create two widget buttons for Play and Stop. The player will press play when they think they have the platform positioned correctly, and once the simulation is active, they can touch the Stop button at any time to try again in case they were unsuccessful in directing the character to the goal.

If you take the project and run it in the Corona Simulator, you’ll see that we have a rather complete little physics-based game. Of course, this game really only serves as one level, but it’s enough to show you how fast and easy it is to create fun, visually-pleasing games using the Corona SDK. If we were to add more levels and obstacles, it’s easy to see that this little creation could potentially have what it takes to stand up to the “big boys” in the App Store.

If you feel inspired to create your own mobile games and apps for iOS or Android, be sure visit Ansca to sign up for a developer account, download the Corona SDK, read more tutorials and connect with tons of friendly developers who are willing to help you with any problems you may have, no matter what your level of experience currently is.

Thank you for reading 5 articles this month* Join now for unlimited access

Enjoy your first month for just £1 / $1 / €1

*Read 5 free articles per month without a subscription

Join now for unlimited access

Try first month for just £1 / $1 / €1

The Creative Bloq team is made up of a group of design fans, and has changed and evolved since Creative Bloq began back in 2012. The current website team consists of eight full-time members of staff: Editor Georgia Coggan, Deputy Editor Rosie Hilder, Deals Editor Beren Neale, Senior News Editor Daniel Piper, Digital Arts and Design Editor Ian Dean, Tech Reviews Editor Erlingur Einarsson and Ecommerce Writer Beth Nicholls and Staff Writer Natalie Fear, as well as a roster of freelancers from around the world. The 3D World and ImagineFX magazine teams also pitch in, ensuring that content from 3D World and ImagineFX is represented on Creative Bloq.