Quantcast
Channel: Envato Tuts+ Code - Mobile Development
Viewing all articles
Browse latest Browse all 1836

Create a Plane Fighting Game in Corona: Gameplay

$
0
0
Final product image
What You'll Be Creating

Introduction

In the first part of this series, we managed to get the start screen showing and were able to transition to the gamelevel screen. In this tutorial, we continue where we left of and start implementing the gameplay.

1. Local Variables

Open gamelevel.lua, the file we created in the first tutorial, and add the following below the line local scene = storyboard.newScene().

local playerSpeedY = 0
local playerSpeedX = 0
local playerMoveSpeed = 7
local playerWidth  = 60
local playerHeight = 48
local bulletWidth  = 8
local bulletHeight =  19
local islandHeight = 81
local islandWidth = 100
local numberofEnemysToGenerate = 0
local numberOfEnemysGenerated = 0
local playerBullets = {} -- Holds all the bullets the player fires
local enemyBullets = {} -- Hold the bullets from "all" enemy planes
local islands = {} --  Holds all the islands
local planeGrid = {} -- Holds 0 or 1 (11 of them for making a grid system)
local enemyPlanes = {}  -- Holds all of the enemy planes
local livesImages = {}  -- Holds all of the "free life" images
local numberOfLives = 3
local freeLifes = {} -- Holds all the ingame free lives
local playerIsInvincible = false
local gameOver = false
local numberOfTicks = 0 -- A number that is incremented each frame of the game
local islandGroup -- A group to hold all of the islands 
local planeGroup -- A group that holds all the planes, bullets, etc
local player
local  planeSoundChannel -- SoundChannel for the plane sound
local firePlayerBulletTimer
local generateIslandTimer
local fireEnemyBulletsTimer
local generateFreeLifeTimer
local rectUp -- The "up" control on the DPAD
local rectDown -- The "down" control on the DPAD
local rectLeft -- The "left" control on the DPAD
local rectRight -- The "right" control on the DPAD

Most of these are self-explanatory, but I've included comments for clarification. From here on out, all code should be inserted above the line return scene.

2. createScene

Start by adding the createScene function to main.lua. The createScene function is called when the scene's view doesn't yet exist. We'll add the game's display objects in this function.

function scene:createScene( event )
    local group = self.view
end
scene:addEventListener( "createScene", scene )

3. setupBackground

function setupBackground ()
    local background = display.newRect( 0, 0, display.contentWidth, display.contentHeight)
    background:setFillColor( 0,0,1)
    scene.view:insert(background)
end

In setupBackground, we create a blue background using the Display object's newRect method. The setFillColor method takes RGB values, as percentages. Invoke the setupBackground function in createScene as shown below.

function scene:createScene( event )
    local group = self.view
    setupBackground()
end

4. setupGroups

The setupGroups function instantiates the islandGroup and planeGroup groups, and inserts them into the scene's view. The GroupObject is a special type of display object into which you can add other display objects. It's important to first add the islandGroup to the view to make sure the islands are below the planes.

function setupGroups()
    islandGroup = display.newGroup()
    planeGroup = display.newGroup()
    scene.view:insert(islandGroup)
    scene.view:insert(planeGroup)
end

Invoke the setupGroups function in createScene as shown below.

function scene:createScene( event )
    local group = self.view
    setupBackground()
    setupGroups()
end

5. setupDisplay

The setupDisplay function draws a black rectangle at the bottom of the screen and inserts dpad and plane images into the view.

function setupDisplay ()
    local tempRect = display.newRect(0,display.contentHeight-70,display.contentWidth,124);
    tempRect:setFillColor(0,0,0);
    scene.view:insert(tempRect)
    local logo = display.newImage("logo.png",display.contentWidth-139,display.contentHeight-70);
    scene.view:insert(logo)
    local dpad = display.newImage("dpad.png",10,display.contentHeight - 70)
    scene.view:insert(dpad)
end

Again, invoke this function in createScene as shown below.

function scene:createScene( event )
    local group = self.view
    setupBackground()
    setupGroups()
    setupDisplay()
end

6. setupPlayer

The setupPlayer function simply adds the player image to the screen. The Display object comes with two read-only properties, contentWidth and contentHeight, representing the original width and height of the content in pixels. These values default to the screen width and height, but may have other values if you're using content scaling in config.lua. We use these properties to align the player in the  scene.

function setupPlayer()
    player = display.newImage("player.png",(display.contentWidth/2)-(playerWidth/2),(display.contentHeight - 70)-playerHeight)
    player.name = "Player"
    scene.view:insert(player)
end

Invoke the setupPlayer function in createScene.

function scene:createScene( event )
    local group = self.view
    setupBackground()
    setupGroups()
    setupDisplay()
    setupPlayer()
end

7. setupLivesImages

The setupLivesImages function sets up six life images and positions them at the top left of the screen. We then insert these images into the livesImages table, so that we're able to reference them later. Lastly, we make sure that only the first three images are visible.

function setupLivesImages()
for i = 1, 6 do
      local tempLifeImage = display.newImage("life.png",  40* i - 20, 10)
      table.insert(livesImages,tempLifeImage)
      scene.view:insert(tempLifeImage)
      if( i > 3) then
           tempLifeImage.isVisible = false;
      end
end
end

The setupLivesImages function is also invoked in the createScene function.

function scene:createScene( event )
        local group = self.view
         setupBackground()
         setupGroups()
         setupDisplay()
         setupPlayer()
         setupLivesImages()
end

8. setupDPad

The setupDPad function sets up the four rectangles rectUp, rectDown, rectLeft, and rectRight. We carefully position them on top of the dpad image, configure them to not be visible, and make sure the isHitTestable property is set to true.

If you set display objects to not be visible, you're initially unable to interact with them. However, by setting the isHitTestable property to true, this behavior is overridden.

function setupDPad()
    rectUp = display.newRect( 34, display.contentHeight-70, 23, 23)
    rectUp:setFillColor(1,0,0)
    rectUp.id ="up"
    rectUp.isVisible = false;
    rectUp.isHitTestable = true;
    scene.view:insert(rectUp)

    rectDown = display.newRect( 34,display.contentHeight-23, 23,23)
    rectDown:setFillColor(1,0,0)
    rectDown.id ="down"
    rectDown.isVisible = false;
    rectDown.isHitTestable = true;
    scene.view:insert(rectDown)

    rectLeft = display.newRect( 10,display.contentHeight-47,23, 23)
    rectLeft:setFillColor(1,0,0)
    rectLeft.id ="left"
    rectLeft.isVisible = false;
    rectLeft.isHitTestable = true;
    scene.view:insert(rectLeft)

    rectRight= display.newRect( 58,display.contentHeight-47, 23,23)
    rectRight:setFillColor(1,0,0)
    rectRight.id ="right"
    rectRight.isVisible = false;
    rectRight.isHitTestable = true;
    scene.view:insert(rectRight)
end

You've guessed it. This function is also invoked in createScene.

function scene:createScene( event )
    local group = self.view
    setupBackground()
    setupGroups()
    setupDisplay()
    setupPlayer()
    setupLivesImages()
    setupDPad()
end

9. resetPlaneGrid

The resetPlaneGrid function resets the planeGrid table and inserts eleven zeros. The planeGrid table imitates eleven spots across the x axis, in which an enemy plane can be positioned. This will make more sense once we start generating enemy planes.

function resetPlaneGrid()
planeGrid = {}
     for i=1, 11 do
         table.insert(planeGrid,0)
     end
end

Invoke this function in createScene.

function scene:createScene( event )
    local group = self.view
    setupBackground()
    setupGroups()
    setupDisplay()
    setupPlayer()
    setupLivesImages()
    setupDPad()
    resetPlaneGrid()
end

10. enterScene

Now that all the display objects are in place, it's time to add event listeners, timers, etc. If you recall from the previous part of this tutorial, the enterScene function is a good place to set these up. Start by inserting the following code snippet.

function scene:enterScene( event )
    local group = self.view
end
scene:addEventListener( "enterScene", scene )

11. Removing the Previous Storyboard

When we enter this scene, we need to remove the previous scene. Add the following code to the enterScene function to do this.

local previousScene = storyboard.getPrevious()
storyboard.removeScene(previousScene)
When you enter a new scene, the previous scene you were on can be referenced by calling getPrevious on the storyboard object. We remove it completely from the storyboard by calling removeScene on the storyboard object.

12. Add Event Listeners to Dpad Rectangles

Add the following code below the code you entered in the previous step. This code snippet adds touch listeners to each of the rectangles, invoking movePlane with every touch. Let's take a look at this movePlane function in the next step.

rectUp:addEventListener( "touch", movePlane)
rectDown:addEventListener( "touch", movePlane)
rectLeft:addEventListener( "touch", movePlane)
rectRight:addEventListener( "touch", movePlane)

13.movePlane

The movePlane function is responsible for setting the planes speed. We check if the touch event's phase is equal to began, which means the player has touched down but not lifted their finger back up. If this is true, we set the speed and direction according to which rectangle was touched. If the touch event's phase is equal to ended, then we know the player has lifted their finger, which means we set the speed to 0.

function movePlane(event)
    if event.phase == "began" then
        if(event.target.id == "up") then
          playerSpeedY = -playerMoveSpeed
        end
        if(event.target.id == "down") then
          playerSpeedY = playerMoveSpeed
        end
        if(event.target.id == "left") then
          playerSpeedX = -playerMoveSpeed
        end
        if(event.target.id == "right") then
          playerSpeedX = playerMoveSpeed
        end
    elseif event.phase == "ended" then
        playerSpeedX = 0
        playerSpeedY = 0 
   end
end

14. PlaneSound

Let's add some sound to our game. Add the following code snippet to the enterScene function. It loads and plays planesound.mp3. By setting the loops property to -1, the sound will loop forever. If you want to learn more about audio in Corona, be sure to check out the documentation.

local planeSound = audio.loadStream("planesound.mp3")
planeSoundChannel = audio.play( planeSound, {loops=-1} )

15. enterFrame Event

We also add a runtime event listener named enterFrame that will call thegameLoop function. The frequency with which the enterFrame event occurs depends on the frames per second (FPS) value you set in config.lua. In our example, it will be called 30 times per second. Add this event listener in the enterScene function.

 Runtime:addEventListener("enterFrame", gameLoop)

16. gameLoop

In the gameLoop function we update the sprite positions and perform any other logic that needs to take place every frame. If you are interested in reading more on the topic of game loops, Michael James Williams wrote a great article that explains how a common game loop works. Add the following code snippet.


function gameLoop()
    movePlayer()
end

17.movePlayer

The movePlayer function manages the moving of the player's plane. We move the plane according to the playerSpeedX and playerSpeedY values, which will either be 7 or 0, depending on whether the player is touching on the DPad or not. Refer back to the movePlane function if this is unclear. We also do some bounds checking, making sure the plane cannot move off-screen.

function movePlayer()
    player.x = player.x + playerSpeedX
    player.y = player.y + playerSpeedY
    if(player.x < 0) then
        player.x = 0
   end
   if(player.x > display.contentWidth - playerWidth) then
       player.x = display.contentWidth - playerWidth
   end
   if(player.y   < 0) then
       player.y = 0
  end
  if(player.y > display.contentHeight - 70- playerHeight) then
      player.y = display.contentHeight - 70 - playerHeight
  end
end

If you test the game now, you should be able to navigate the plane around the screen using the DPad.

Conclusion

This brings the second tutorial of this series to a close. In the next installment of this series, we will continue with the gameplay. Thanks for reading and see you there.

2014-07-09T16:45:28.000Z2014-07-09T16:45:28.000ZJames Tyner

Viewing all articles
Browse latest Browse all 1836

Trending Articles