The last two posts made a simple game with a tiled playing field and enemies that cross the screen. Now I’d like to add some defense. The goal of the defense elements is to keep enemies from crossing the screen and reaching the other side.
The first step is to create a factory function to generate defensive elements for the game. As a first step we’ll start with a single type of defense and use a red rectangle for art. Here’s a simple function that generates a red square and places at x and y coordinates passed to the function.
local function make_defense( x, y ) local defense = display.newRect( 0, 0, 32, 32 ) defense:setFillColor( 200, 0, 0 ) game_group:insert( defense ) defense.x = x defense.y = y return defense -- Return the new defense end
This function returns the newly created defense. This allows any other function that calls make_defense() to work with the newly created defense, saving a reference, or adding or editing properties of the defense.
Touching the grid
Our defenses should end up on the tile grid. We can use the x and y of the grid square to position the new defense. The grid square can also keep track of it’s contents which we can use to make sure we don’t add more than one defense per square.
Add an event listener to each grid square inside the make_grid() function:
tile:addEventListener( "touch", touch_tile )
Now define touch_tile(). This will have to go above make_grid(), and the make_defense() function will have to be placed above touch_tile().
local function touch_tile( event ) local phase = event.phase if phase == "began" then local tile = event.target local tile_x = tile.x local tile_y = tile.y make_defense( tile_x, tile_y ) end end
Here we check the event phase. If the phase is “began” then we’ll add a defense at this tile. First get a reference to the tile then get that tile’s x and y. Last call make_defense and pass the tile coordinates.
Testing, at this stage tapping a tile should display a red square centered on that tile.
There are a few problems. Defense elements will appear above some enemies and below others. Each new display item is added to the top of the display list, and appears in front of already existing display items in a group. Items in a group stack at the position of their group inside the parent element.
Using groups to layer elements
As a first idea let’s add a group for each type of element: tile, defense, and alien. We’ll place all of these groups into game_group. Then add each element, tile, alien and defense, as it is created to it’s name group. This will make all like elements stack together.
local game_group = display.newGroup() local defense_group = display.newGroup() -- make a group to hold each class local alien_group = display.newGroup() -- local tile_group = display.newGroup() game_group:insert( tile_group ) -- Add each group to the main group game_group:insert( defense_group ) game_group:insert( alien_group )
You’ll need to edit the make_grid(), make_alien(), and make_defense() functions so these add the elements they create to the proper group.
Testing again, this time all of the defense elements will always be above the background tiles and below the enemies.
Creating a single defense in each grid square
There is a problem that a new defense is created with each touch on a tile. This won’t be visible, since the defense rectangles are stacked on above another, but it will be happening.
To fix this assign each tile a variable to keep track of whether it has a defense or not.
tile.has_defense = false
Next add an if statement to the touch_tile() handler.
if tile.has_defense == false then -- Check that tile has no defense tile.has_defense = true -- mark this tile as now having a defense local tile_x = tile.x local tile_y = tile.y make_defense( tile_x, tile_y ) end
Now, if a tile is touched, we first check it for a defense. If no defense is present, tile.has_defense = false, then we add a defense and set tile.has_defense to true. On the next touch no defense would be added.