# Create a Space Invaders Game in Corona: Finishing Gameplay

This post is part of a series called Create a Space Invaders Game in Corona.
Create a Space Invaders Game in Corona: Implementing Gameplay

In the previous part of this series, we got the player's ship moving, got the invaders moving, and detected when a player bullet had hit an invader. In this final part of the series, we will get the invaders attacking the player, handle levels, and add the ability for the player to die.

## 1. Firing Bullets

Every so often one of the invaders fires a bullet. We'll use a timer to accomplish this. Add the following code to gamelevel.lua.

 1 function fireInvaderBullet()  2  if(#invadersWhoCanFire >0) then  3  local randomIndex = math.random(#invadersWhoCanFire)  4  local randomInvader = invadersWhoCanFire[randomIndex]  5  local tempInvaderBullet = display.newImage("laser.png", randomInvader.x , randomInvader.y + invaderSize/2)  6  tempInvaderBullet.name = "invaderBullet"  7  scene.view:insert(tempInvaderBullet)  8  physics.addBody(tempInvaderBullet, "dynamic" )  9  tempInvaderBullet.gravityScale = 0  10  tempInvaderBullet.isBullet = true  11  tempInvaderBullet.isSensor = true  12  tempInvaderBullet:setLinearVelocity( 0,400)  13  table.insert(invaderBullets, tempInvaderBullet)  14  else  15  levelComplete()  16  end  17 end 

In this function, we first check if the invadersWhoCanFire table has at least one element in it. If that's the case, then we execute the code in the if statement. Otherwise it means the level is over and we invoke the levelComplete function.

There will always be at least one invader who can fire a bullet until you kill the last invader, at which point the invadersWhoCanFire table will be empty.

Inside the if statement, we generate a random number randomIndex depending on how many items are in the invadersWhoCanFire table. We then choose that item, randomInvader, from the invadersWhoCanFire table.

We create a bullet image, give it a name property so we can identify it later, insert it into the scene, and set the same properties as we did on the player's bullet. Finally, we insert the bullet into the invaderBullets table so we can reference it later.

We now need to set up the timer. Add the following to the scene:show method.

 1 function scene:show(event)  2  if ( phase == "did" ) then  3  --SNIP--  4  Runtime:addEventListener( "collision", onCollision )  5  invaderFireTimer = timer.performWithDelay(1500, fireInvaderBullet,-1)  6  end  7 end 

Every 1500 milliseconds fireInvaderBullet is invoked. Note that the last parameter we pass in is -1, which means the timer repeats forever. Whenever you create a timer that repeats forever, you should eventually cancel it. We do this in the scene:hide function as shown below.

 1 function scene:hide(event)  2  if ( phase == "will" ) then  3  --SNIP--  4  Runtime:removeEventListener( "collision", onCollision )  5  timer.cancel(invaderFireTimer)  6  end  7 end 

## 2. Removing Bullets

Like the player's bullets, the invaders' bullets will move off-screen and keep moving, taking up valuable memory. To remedy this, we remove them just like we did with the player's bullets.

 1 function checkInvaderBulletsOutOfBounds()  2  if (#invaderBullets > 0) then  3  for i=#invaderBullets,1,-1 do  4  if(invaderBullets[i].y > display.contentHeight) then  5  invaderBullets[i]:removeSelf()  6  invaderBullets[i] = nil  7  table.remove(invaderBullets,i)  8  end  9  end  10  end  11 end 

This code is very similar to checking if the player's bullets are out of bounds so I won't discuss its implementation in detail.

## 3. Detecting a Hit

### Step 1: Collision Detection

The next step is to detect whether an invader's bullet has hit the player. Add the following code to the onCollision function.

 1 function onCollision(event)  2  if ( event.phase == "began" ) then  3  --SNIP--  4  if(event.object1.name == "player" and event.object2.name == "invaderBullet") then  5  table.remove(invaderBullets,table.indexOf(invaderBullets,event.object2))  6  event.object2:removeSelf()  7  event.object2 = nil  8  if(playerIsInvincible == false) then  9  killPlayer()  10  end  11  return  12  end  13   14  if(event.object1.name == "invaderBullet" and event.object2.name == "player") then  15  table.remove(invaderBullets,table.indexOf(invaderBullets,event.object1))  16  event.object1:removeSelf()  17  event.object1 = nil  18  if(playerIsInvincible == false) then  19  killPlayer()  20  end  21  return  22  end  23  end  24 end 

Like before, we do not know what object event.object1 and event.object2 will be so we use two if statements to check both situations. We remove the invader's bullet from the invaderBullets table, remove it from the display, and set it to nil. If the player isn't invincible, we kill the it.

### Step 2: Killing the Player

When we kill the player, we give him a short time of invincibility. This gives the user time to regain focus on the game. If the numberOfLives variable is equal to 0, we know the game is over and transition to the start scene where the user can begin a  new game.

 1 function killPlayer()  2  numberOfLives = numberOfLives- 1;  3  if(numberOfLives <= 0) then  4  gameData.invaderNum = 1  5  composer.gotoScene("start")  6  else  7  playerIsInvincible = true  8  spawnNewPlayer()  9  end  10 end 

### Step 3: Spawning a New Player

The spawnNewPlayer function makes the player fade in and out for a few seconds. It's a nice effect to let the user know that the ship is temporarily invincible.

 1 function spawnNewPlayer()  2  local numberOfTimesToFadePlayer = 5  3  local numberOfTimesPlayerHasFaded = 0  4   5  local function fadePlayer()  6  player.alpha = 0;  7  transition.to( player, {time=400, alpha=1, })  8  numberOfTimesPlayerHasFaded = numberOfTimesPlayerHasFaded + 1  9  if(numberOfTimesPlayerHasFaded == numberOfTimesToFadePlayer) then  10  playerIsInvincible = false  11  end  12  end  13   14  fadePlayer()  15  timer.performWithDelay(400, fadePlayer,numberOfTimesToFadePlayer)  16 end 

We use a local function, fadePlayer, that uses the transition library to modify the alpha value of the player. We keep track of how many times the player has faded in and out, and set the player's invincibility to false once we reach the numberOfTimesToFadePlayer. We use a timer to call the fadePlayer function for however many times numberOfTimesToFadePlayer is equal to.

Run the game to test this out. The player should die when an invader's bullet hits the ship. If three bullets hit the ship, you should be taken to the start scene where you can start a new game.

To make this easier to test, comment out the call to moveInvaders in the gameLoop function as shown below.

 1 function gameLoop()  2  checkPlayerBulletsOutOfBounds()  3  --moveInvaders()  4  checkInvaderBulletsOutOfBounds()  5 end 

## 4. Completing a Level

If you've managed to kill every invader, the game would have called the levelComplete function, which doesn't exist yet. Let fix that. Add the following code block.

 1 function levelComplete()  2  gameData.invaderNum = gameData.invaderNum + 1  3  if(gameData.invaderNum <= gameData.maxLevels) then  4  composer.gotoScene("gameover")  5  else  6  gameData.invaderNum = 1  7  composer.gotoScene("start")  8  end  9 end 

We increment gameData.invaderNum and, if it is less than gameData.maxLevels, we transition to the gameover scene. Otherwise, the player has completed every level and we reset gameData.invaderNum to 1. We transition to the start scene where the player can begin a new game.

An easy way to test this is by commenting out the call to moveInvaders in the gameLoop function and use the buttons to move the ship. If that's still too hard, then you can also comment out the two calls to killPlayer in the onCollision method.

## 5. Game Over

Add the following code to gameover.lua to implement the game over scene.

 1 local composer = require("composer")  2 local scene = composer.newScene()  3 local starFieldGenerator = require("starfieldgenerator")  4 local pulsatingText = require("pulsatingtext")  5 local nextLevelButton  6 local starGenerator  7 function scene:create( event )  8  local group = self.view  9  starGenerator = starFieldGenerator.new(200,group,5)  10  local invadersText = pulsatingText.new("LEVEL COMPLETE", display.contentCenterX, display.contentCenterY-200,"Conquest", 20,group )  11  invadersText:setColor( 1, 1, 1 )  12  invadersText:pulsate()  13  nextLevelButton = display.newImage("next_level_btn.png",display.contentCenterX, display.contentCenterY)  14  group:insert(nextLevelButton)  15  end  16 17 function scene:show( event )  18  local phase = event.phase  19  composer.removeScene("gamelevel" )  20  if ( phase == "did" ) then  21  nextLevelButton:addEventListener("tap",startNewGame)  22  Runtime:addEventListener ( "enterFrame", starGenerator)  23  end  24 end  25 26 function scene:hide(event )  27  local phase = event.phase  28  if ( phase == "will" ) then  29  Runtime:removeEventListener("enterFrame", starGenerator)  30  nextLevelButton:removeEventListener("tap",startNewGame)  31  end  32 end  33 34 35 function startNewGame()  36  composer.gotoScene("gamelevel")  37 end  38 scene:addEventListener( "create", scene )  39 scene:addEventListener( "show", scene )  40 scene:addEventListener( "hide", scene )  41 42 return scene 

This code is very similar to the start scene so you should be familiar with it by now.

## 6. Colliding with an Invader

The last collision check we need to perform is a collision between the player and on of the invaders. Add the following code block to the onCollision method we saw earlier.

 1 function onCollision(event)  2  --SNIP--  3  if ( event.phase == "began" ) then  4  --SNIP--  5  if(event.object1.name == "player" and event.object2.name == "invader") then  6  numberOfLives = 0  7  killPlayer()  8  end  9   10  if(event.object1.name == "invader" and event.object2.name == "player") then  11  numberOfLives = 0  12  killPlayer()  13  end  14  end 

As usual, we need to check both collision situations. We set the numberOfLives to 0 and call killPlayer. By setting numberOfLives to 0 and invoking killPlayer, the game is over and the game transitions to the start scene.

## 7. More Features

This completes our game, but I suggest you try to expand the game with a few additional features. For example, you could display the player's lives in a HUD.

I have also included a UFO graphic in the source files. You could try make a UFO randomly appear and if the player hits it with a bullet give them an extra life.

If you need help with these concepts, then check out my Plane Fighting Game series on Tuts+.

## Conclusion

If you've followed this series, then you should now have a fully functional game similar to the original Space Invaders. Expand on it and make it your own. I hope you found this tutorial helpful and have learned some new techniques. Thank you for for reading.