Corona SDK: Create a Helicopter Obstacles Game

Student iconAre you a student? Get a yearly Tuts+ subscription for $45 →

In this tutorial, I'll be showing you how to create an obstacles avoiding game using the Corona SDK. You'll learn more about touch controls, collision detection, and physics. The objective of the game is to avoid as many obstacles as you can to obtain the highest score. Let's get started.

1. Application Overview

App Overview

Using ready-made graphics, we'll create an entertaining game using the Lua programming language and the Corona SDK APIs. The player will be able to move a helicopter on the screen and needs to avoid any obstacles it comes across. You can modify the parameters in the code to customize the game.

2. Target Device

Target Device

The first thing we have to do is select the platform we want to run our application on so we're able to choose the size for the images we'll use.

The iOS platform has the following requirements:

  • iPad 1/2/Mini: 1024px x 768px, 132 ppi
  • iPad Retina: 2048px x 1536px, 264 ppi
  • iPhone/iPod Touch: 320px x 480px, 163 ppi
  • iPhone/iPod Retina: 960px x 640px, 326 ppi
  • iPhone 5/iPod Touch: 1136px x 640px, 326 ppi

Because Android is an open platform, there are many different devices and resolutions. A few of the more common screen characteristics are:

  • Asus Nexus 7 Tablet: 800px x 1280px, 216 ppi
  • Motorola Droid X: 854px x 480px, 228 ppi
  • Samsung Galaxy SIII: 720px x 1280px, 306 ppi

In this tutorial, we'll be focusing on the iOS platform in terms of graphics. In particular, we'll be developing for the iPhone and iPod Touch. However, the code of this tutorial can also be used in you target the Android platform.

3. Interface


We'll use a simple user interface involving multiple shapes, buttons, bitmaps, and more. The graphics that we'll use for this tutorial can be found in the project included with this tutorial.

4. Export Graphics

Export Graphics

Depending on the device you've selected, you may need to convert the graphics to the recommended resolution (ppi), which you can do in your favorite image editor. I used the Adjust Size… option in the Tools menu in the Preview application on OS X. Remember to give the images a descriptive name and save them in your project folder.

5. Application Configuration

We'll use a configuration file, config.lua, to make the application go full screen across devices. The configuration file shows the original screen size and the method used to scale the content in case the application is run on a different resolution.

application =
    content =
        width = 320,
        height = 480,
        scale = "letterbox"

6. main.lua

Let's write the actual application. Open your preferred Lua editor. Any plain text editor will work, but it is recommended to use a text editor that has syntax highlighting. Create a new file and save it as main.lua in your project folder.

7. Code Structure

We'll structure our code as if it were a class. If you're familiar with ActionScript or Java, you should find the project structure familiar.

Necessary Classes

Variables and Constants

Declare Functions

    constructor (Main function)

    class methods (other functions)

call Main function

8. Hide Status Bar


This code snippet hides the status bar. The status bar is the bar at the top of the device's screen that shows the time, signal, and other indicators.

9. Import Physics

We'll use the physics library to handle collisions. Import the library using the code snippet shown below.

-- Physics

local physics = require('physics')

10. Background


A simple background for the application's user interface. The code snippet below draws the background to the screen.

-- Graphics

-- [Background]

local gameBg = display.newImage('gameBg.png')

11. Title View

Title View

This is the title view. It's the first interactive screen to appear in our game. These variables store its components.

-- [Title View]

local title
local playBtn
local creditsBtn
local titleView

12. Credits View

Credits View

The credits view shows the credits and copyright of the application. This variable is used to store it.

-- [CreditsView]

local creditsView

13. Instructions Message


A message with instructions will appear at the start of the game and it will disappear after the first tap.

-- Instructions

local ins

14. Helicopter


This is the helicopter graphic. The player will control the helicopter using touch controls.

-- Helicopter

local helicopter

15. Blocks


The blocks are the obstacles the player needs to avoid.

-- Blocks

local blocks = {}

16. Alert


The alert is displayed when the player misses the ball and the game is over. It displays a message and ends the game.

-- Alert

local alertView

17. Sounds


To liven up the game, we'll use sound effects. The sounds used in the game were obtained from as3soundfxr. I found the background music on playonloop.

-- Sounds

local bgMusic = audio.loadStream('POL-rocket-station-short.wav')
local explo = audio.loadSound('explo.wav')

18. Variables

The following code snippet shows the variables that we'll use. Read the comments to understand what each variable is used for.

-- Variables

local timerSrc --Blocks timer
local yPos = {90, 140, 180} --Possible positions for the blocks
local speed = 5 --Block speed
local speedTimer --Increases blocks speed
local up = false --Used to determine if helicopter is going up
local impulse = -60 --physics value to make helicopter go up

19. Declare Functions

Declare all functions as local at the start.

-- Functions

local Main = {}
local startButtonListeners = {}
local showCredits = {}
local hideCredits = {}
local showGameView = {}
local gameListeners = {}
local createBlock = {}
local movePlayer = {}
local increaseSpeed = {}
local update = {}
local alert = {}

20. Constructor

Next, we create the function that will initialize the game logic.

function Main()
  -- code...

21. Add Title View

We start by placing the title view in the stage and call a function that will add tap listeners to the buttons.

function Main()
  titleBg = display.newImage('titleBg.png')
  playBtn = display.newImage('playBtn.png', 220, 178)
  creditsBtn = display.newImage('creditsBtn.png', 204, 240)
  titleView = display.newGroup(titleBg, playBtn, creditsBtn)


22. Start Button Listeners

The following function adds the necessary listeners to the TitleView's buttons.

function startButtonListeners(action)
  if(action == 'add') then
    playBtn:addEventListener('tap', showGameView)
    creditsBtn:addEventListener('tap', showCredits)
    playBtn:removeEventListener('tap', showGameView)
    creditsBtn:removeEventListener('tap', showCredits)

23. Show Credits

The credits screen is shown when the user taps the about button. A tap listener is added to the credits view to dismiss it when the user taps it.

function showCredits:tap(e)
  playBtn.isVisible = false
  creditsBtn.isVisible = false
  creditsView = display.newImage('credits.png', -110, display.contentHeight-80), {time = 300, x = 55, onComplete = function() creditsView:addEventListener('tap', hideCredits) end})

24. Hide Credits

When the user taps the credits view, it is animated out of the stage and remove.

function hideCredits:tap(e)
  playBtn.isVisible = true
  creditsBtn.isVisible = true, {time = 300, y = display.contentHeight+creditsView.height, onComplete = function() creditsView:removeEventListener('tap', hideCredits) display.remove(creditsView) creditsView = nil end})

25. Show Game View

When the play button is tapped, the title view is animated off the screen and the game is revealed. There are a number of moving parts so we'll take a closer look at each of them.

function showGameView:tap(e), {time = 300, x = -titleView.height, onComplete = function() startButtonListeners('rmv') display.remove(titleView) titleView = nil end})

26. Instructions Message

The following code snippet adds the instructions message.

ins = display.newImage('ins.png', 180, 270)
  transition.from(ins, {time = 200, alpha = 0.1, onComplete = function() timer.performWithDelay(2000, function(), {time = 200, alpha = 0.1, onComplete = function() display.remove(ins) ins = nil end}) end) end})

27. Score TextField

The following code snippet creates a text field that shows the player's current score in the top-right of the stage.

-- TextFields

  scoreTF = display.newText('0', 450, 5, 'Marker Felt', 14)
  scoreTF:setTextColor(255, 255, 255)

28. Helicopter

Next, it is time to add the helicopter graphic to the stage as shown below.

-- Helicopter

  helicopter = display.newImage('helicopter.png', 23, 152)

29. Walls

In the following code snippet, we use the Corona graphics API to create several lines that we'll add to the physics simulation a bit later in this tutorial. They will be used to detect collisions with the helicopter.

-- Walls

  local top = display.newRect(0, 60, 480, 1)
  top:setFillColor(34, 34, 34)
  local bottom = display.newRect(0, 260, 480, 1)
  bottom:setFillColor(34, 34, 34)

30. Physics

Next, we need to add the necessary physics to each object.

-- Add physics

  physics.addBody(top, 'static')
  physics.addBody(bottom, 'static')

31. Start Game

We create a group for the blocks, invoke the gameListeners function, and start the background music.

  blocks = display.newGroup()
  gameListeners('add'), {loops = -1, channel = 1})

32. Game Listeners

The following code snippet may seem complex, but it simply adds a few listeners to start the game logic.

function gameListeners(action)
  if(action == 'add') then
    gameBg:addEventListener('touch', movePlayer)
    Runtime:addEventListener('enterFrame', update)
    timerSrc = timer.performWithDelay(1300, createBlock, 0)
    speedTimer = timer.performWithDelay(5000, increaseSpeed, 5)
    helicopter:addEventListener('collision', onCollision)
    gameBg:addEventListener('touch', movePlayer)
    Runtime:removeEventListener('enterFrame', update)
    timerSrc = nil
    speedTimer = nil
    helicopter:removeEventListener('collision', onCollision)

33. Create a Block

As its name indicates, the createBlock function creates a block and draws it to the screen. The resulting object is added to the physics engine to check for collisions.

function createBlock()
  local b
  local rnd = math.floor(math.random() * 4) + 1
  b = display.newImage('block.png', display.contentWidth, yPos[math.floor(math.random() * 3)+1]) = 'block'
  -- Block physics
  physics.addBody(b, 'kinematic')
  b.isSensor = true

34. Move Function

In the movePlayer function, we update the up variable. As long as its value is equal to true, the update function moves the helicopter up.

function movePlayer(e)
  if(e.phase == 'began') then
    up = true
  if(e.phase == 'ended') then
    up = false
    impulse = -60

35. Increase Speed

To make the game more interesting, a timer increases the speed every five seconds. An icon is displayed to alert the player of change in speed.

function increaseSpeed()
  speed = speed + 2
  -- Icon
  local icon = display.newImage('speed.png', 204, 124)
  transition.from(icon, {time = 200, alpha = 0.1, onComplete = function() timer.performWithDelay(500, function(), {time = 200, alpha = 0.1, onComplete = function() display.remove(icon) icon = nil end}) end) end})

36. Move Helicopter

The update function checks the value of up and moves the helicopter up if it is equal to true.

function update(e)
  -- Move helicopter up
  if(up) then
    impulse = impulse - 3
    helicopter:setLinearVelocity(0, impulse)

37. Move Blocks

Next, it is time to move the blocks. We use the speed variable to determine how many pixels the blocks should be moved every frame.

-- Move Blocks
  if(blocks ~= nil)then
    for i = 1, blocks.numChildren do
      blocks[i].x = blocks[i].x - speed

38. Update Score

The algorithm to update the score is simple. The score is incremented by one every frame for as long as the helicopter hasn't crashed. Simple. Right?

  -- Score
  scoreTF.text = tostring(tonumber(scoreTF.text) + 1)

39. Collisions

The onCollision function verifies if the helicopter has collided with a block. If a collision was detected, we play a sound effect, an explosion, remove the graphics, and show an alert to the player.

function onCollision(e)

40. Alert

The alert function creates an alert view and shows it to the user. The game then ends.

function alert()
  alert = display.newImage('alert.png', (display.contentWidth * 0.5) - 105, (display.contentHeight * 0.5) - 55)
  transition.from(alert, {time = 300, xScale = 0.5, yScale = 0.5})

41. Invoke Main Function

In order to start the game, the Main function needs to be invoked. With the rest of the code in place, we do that here.


42. Loading Screen

Loading Screen

On the iOS platform, the file named Default.png is displayed while the application is launching. Add this image to your project's source folder, it will be automatically added by the Corona compiler.

43. Icon


Using the graphics you created earlier, you can now create a nice icon. The dimensions of the icon size for a non-retina iPhone are 57px x 57px, while the retina version needs to be 114px x 114px. The artwork for iTunes is required to be 1024px x 1024px. I suggest creating the iTunes artwork first and then creating the smaller sized images by scaling the iTunes artwork down to the correct dimensions. There is no need to make the application icon glossy or add rounded corners as this is taken care of by the operating system for you.

44. Testing in Simulator


It's time to test our application in the simulator. Open the Corona Simulator, browse to your project folder, and click Open. If everything works as expected, you're ready for the final step.

45. Build Project


In the Corona Simulator, go to File > Build and select the target device. Fill out the required fields and click Build. Wait a few seconds and your application is ready to test on a device and/or to be submitted for distribution.


In this tutorial, we've learned about touch listeners, collision detection, physics as well as a few other skills that can be useful in a wide number of games. Experiment with the final result and try to modify the game to create your own version of the game. I hope you liked this tutorial and found it helpful. Thank you for reading.