Corona Starfighter with Corona SDK Part 4

Please note, due to some unforeseen circumstances, I’ve lost my screenshots. If you would like to see screenshots, let me know in the comments!

This is the final part for the game development tutorial on Corona Starfighter with Corona SDK. We’ll wrap things up by adding a game over function, creating enemy ships, creating bullets, and set up collision detection.

Game Over

Within the function scene:create, we’ll create a function called gameOver. This function will get called when the player gets hit. The player will then see a game over background, a game over title, and a button to return the player back to the menu. We’ll also call stopGame() to make sure everything in the game stops.

-- The game over function. Display background, title, and a menu button
gameOver = function()
 local gameOverBackground = display.newRect(sceneGroup, 0, 0, acw, ach)
 gameOverBackground.x = cx
 gameOverBackground.y = cy
 gameOverBackground:setFillColor(0,0,0,0.45)

 local gameOverTitle = display.newImageRect(sceneGroup, "images/gameOver.png", 339, 284)
 gameOverTitle.x = cx
 gameOverTitle.y = cy * 0.65

 local gameOverMenu = display.newImageRect(sceneGroup, "images/toMenu.png", 203, 65)
 gameOverMenu.x = cx
 gameOverMenu.y = gameOverTitle.y + 250
 gameOverMenu:addEventListener("touch", onMenuTouch)

 stopGame() -- stop the game when it's game over
end

Creating Enemy Ships

Next, we’ll create a function that will create enemy ships. The enemy ships start off screen and will transition downwards towards the player. This process is similar to creating the player ship. However, there are a few differences.

The first difference is that we are attaching each enemy ship to a table. This will make sure we can reference an enemy ship and correctly use transitions. The next difference is that we are making enemy ships as sensors. When you make a sensor, the physics body does not respond to physic collisions. Finally, we are using transition.to() to move the enemy ship. I randomized the transition time to give the game a bit of a random feel similar to an actual arcade game. When the transition is done, the enemy ship is removed.

-- Create an enemy ship that spawn at the top of the screen. The ships start off screen to make it look like they are flying in. The x position is a randomly assigned X position.
 createEnemyShips = function()
 enemyCounter = enemyCounter + 1

enemyShip[enemyCounter] = display.newImageRect(sceneGroup, "images/enemyShip.png", 70, 46)
 enemyShip[enemyCounter].x = math.random(left+20, right-20)
 enemyShip[enemyCounter].y = top - 50
 enemyShip[enemyCounter].id = "enemy" -- set an id. This is used for physics collisions.
 physics.addBody( enemyShip[enemyCounter] ) -- add a physics body to our enemy ship. I left this as the default rectangle body. Creating an outline creates overhead and eats up more memory. That shouldn't be a concern in this game, but something to think about.
 enemyShip[enemyCounter].isSensor = true -- by making it a sensor, the enemy ship will not respond to physic collisions

transition.to(enemyShip[enemyCounter], {y=bottom+50, time=math.random(3750,6000), onComplete=function(self) display.remove(self) end}) -- transition.to is what we use to move our enemy ships
 end

Creating Bullets

Now we can create bullets! These bullets will be sensors and will be spawned at the player ship location. I’ve set the y location of each bullet to be slightly in front of the player ship so it looks more natural.

-- Create bullets that spawn in front of the player.
 createBullets = function()
 bulletCounter = bulletCounter + 1

bullet[bulletCounter] = display.newImageRect(sceneGroup, "images/bullet.png", 10, 25)
 bullet[bulletCounter].x = playerShip.x
 bullet[bulletCounter].y = playerShip.y - 40 -- start the bullet in front of the player ship
 bullet[bulletCounter].id = "bullet" -- set an id. This is used for physics collisions.
 physics.addBody( bullet[bulletCounter] ) -- add a physics body to our bullet
 bullet[bulletCounter].isSensor = true -- by making it a sensor, the bullet will not respond to physic collisions

transition.to(bullet[bulletCounter], {y=top-50, time=1500, onComplete=function(self) display.remove(self) end})
 end

Collision Detection

Using physics for collision is an advanced topic because there’s a lot of nuances to cover. For our game, Corona Starfighter, we only need to dive in just enough to get objects colliding.

onGlobalCollision will be a function that runs during that game and will pick up collisions between two physics objects. For example, this function will get triggered when a bullet collides with an enemy or if the enemy collides with the player.

I’ve placed comments within the function below to help you understand the workings of this function. In a nutshell, the function tries to identify what objects are colliding. Based on that collision, it’ll trigger the game over or increase the player score.

-- Create a global collision function that will be trigged when two physics objects collide. In our case, it's bullet-enemy or player-enemy.
onGlobalCollision = function(event)
 local obj1 = event.object1 -- store the objects into obj1 and obj2 for easy reference later
 local obj2 = event.object2

-- Since it's always a bad idea to remove a display object in the middle of collision detection (funky things can happen, it's like taking food right out of your mouth before you swallow), we have a function that's called 1ms after collision happens. This function removes both objects.
 local function removeEnemyAndBullet()
  display.remove(obj1)
  display.remove(obj2)
  increasePlayerScore()
 end

 if ( event.phase == "began" ) then
  -- Detect collision between enemy and bullet. If so, call removeEnemyAndBullet
  if(obj1.id == "enemy" and obj2.id == "bullet") then
   timer.performWithDelay ( 1, removeEnemyAndBullet )
  end
  if(obj1.id == "bullet" and obj2.id == "enemy") then
   timer.performWithDelay ( 1, removeEnemyAndBullet )
  end

  -- Detect collision between enemy and player. If so, call gameOver.
  if(obj1.id == "enemy" and obj2.id == "player") then
   timer.performWithDelay ( 1, gameOver )
  end
  if(obj1.id == "player" and obj2.id == "enemy") then
   timer.performWithDelay ( 1, gameOver )
  end
 end
end

Making the Game Run

Finally, we’ll make our game run by adding the following lines of code to scene:show() in the did phase. These lines will start the timer for enemies, start the timer for bullets, and add the event listener for collision detection.

timerForEnemies = timer.performWithDelay(1000, createEnemyShips, 0)
 timerForBullets = timer.performWithDelay(750, createBullets, 0)
 Runtime:addEventListener( "collision", onGlobalCollision )

Conclusion

And that’s it for building a full game with Corona SDK! Part 4 has covered the final steps for building Corona Starfighter. I sincerely hope you’ve enjoyed reading my tutorial series and if you have questions or comments, please leave them below! You can download the full game template at http://gamebuildingtools.com/product/corona-starfighter-corona-sdk and you can make this game even better. Some ideas would be to add variety to the enemies, ship upgrades, and a health system. If you do expand on this tutorial, I’d love to see them!

Leave a Reply

Your email address will not be published. Required fields are marked *