Time for the enemies to strike back. So far the defenses have it easy, there is no way to remove a defense. There are a lot of things we can do here. In this example I’ll just take a simple step and remove a defense if an enemy intersects it. This will let the game play and tutorial advance slowly. I find I get better results if I build things from smaller steps.
The first step here will be to check if an enemy is intersecting a defense. The earlier hit_test(x,y, bounds) function works well with bullets which are small size. With larger elements the center point of an object may be outside of another object, but the two objects might be overlapping still. To solve this we can use a different type of hit test comparing the bounds of both objects.
Here’s a simple function that tests for overlapping boundaries. This was posted here by jhocking: http://developer.anscamobile.com/code/flashs-hittestobject-emulated-using-contentbounds. I modified the function slightly but it is essentially the same.
local function hit_test_bounds( bounds1, bounds2 ) return bounds1.xMin < bounds2.xMax and bounds1.xMax > bounds2.xMin and bounds1.yMin < bounds2.yMax and bounds1.yMax > bounds2.yMin end
This uses the boundaries of an object. imagine the boundary as a rectangle that just fits the object.
Now we need check for overlap between aliens and defense elements. For this we’ll need to loop through the alien_array and use the function above to check for an overlap with each of the defenses in defense_array. On a true from hit_test_bounds() remove that defense and break the loop.
local function check_enemies() for a = 1, #alien_array, 1 do local alien = alien_array[a] for d = 1, #defense_array, 1 do local defense = defense_array[d] -- Here we're use the new hit_test_bounds() function to check if the defense and alien overlap if hit_test_bounds( alien.contentBounds, defense.contentBounds ) then -- Check for collision remove_defense( defense ) -- Remove this defense on a collision break end end end end
Add a call to this function in the enterFrame. Have to check this each frame.
local function on_enterframe( event ) check_bullets() check_enemies() end
Remember, when creating a defense a timer is added which fires a bullet from the position of the defense. If the defense is removed it’s timer should also be removed. Update remove_defense():
local function remove_defense( defense ) local index = table.indexOf( defense_array, defense ) timer.cancel( defense.timer ) -- Must remove the timer! table.remove( defense_array, index ) display.remove( defense ) end
----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- This example will try ad show enemies that can damage defenses. -- Here a defense that is intersected by an enemy will be removed. display.setStatusBar( display.HiddenStatusBar ) local TILE_ROWS = 9 local TILE_COLS = 5 local TILE_SIZE = 48 local TILE_MARGIN = 1 local BULLET_SPEED = 1000 / 400 local defense_array = {} local alien_array = {} local bullet_array = {} local game_group = display.newGroup() local defense_group = display.newGroup() local alien_group = display.newGroup() local tile_group = display.newGroup() game_group:insert( tile_group ) game_group:insert( defense_group ) game_group:insert( alien_group ) local function remove_bullet( bullet ) local index = table.indexOf( bullet_array, bullet ) transition.cancel( bullet.transition ) table.remove( bullet_array, index ) display.remove( bullet ) end local function make_bullet( x, y ) local bullet = display.newCircle( 0, 0, 5 ) bullet:setFillColor( 0, 0, 0 ) bullet.x = x bullet.y = y table.insert( bullet_array, bullet ) local bt = y * BULLET_SPEED bullet.transition = transition.to( bullet, {y=0, time=bt, onComplete=remove_bullet} ) end local function defense_defend( defense ) for i = 1, #alien_array, 1 do local alien = alien_array[i] if alien.col == defense.col then make_bullet( defense.x, defense.y ) break end end end local function remove_defense( defense ) local index = table.indexOf( defense_array, defense ) timer.cancel( defense.timer ) -- Must remove the timer! table.remove( defense_array, index ) display.remove( defense ) end local function make_defense( x, y ) local defense = display.newRect( 0, 0, 32, 32 ) defense:setFillColor( 200, 0, 0 ) defense_group:insert( defense ) defense.x = x defense.y = y table.insert( defense_array, defense ) defense.timer = timer.performWithDelay( 1000, function() defense_defend( defense ) end, -1 ) return defense end 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 local defense = make_defense( tile_x, tile_y ) defense.col = tile.col end end local function make_grid() for row = 1, TILE_ROWS, 1 do for col = 1, TILE_COLS, 1 do local tile = display.newRect( 0, 0, TILE_SIZE, TILE_SIZE ) tile.x = ( TILE_SIZE + TILE_MARGIN ) * col tile.y = ( TILE_SIZE + TILE_MARGIN ) * row tile.col = col tile.has_defense = false tile:addEventListener( "touch", touch_tile ) tile_group:insert( tile ) end end end local function remove_alien( alien ) local index = table.indexOf( alien_array, alien ) transition.cancel( alien.transition ) table.remove( alien_array, index ) display.remove( alien ) end local function make_alien() local alien = display.newRect( 0, 0, 32, 32 ) alien:setFillColor( 0, 200, 0 ) local col = math.random( 1, TILE_COLS ) alien.col = col alien.x = col * ( TILE_SIZE + TILE_MARGIN ) alien.y = 0 alien.life = 5 local target_y = ( TILE_SIZE + TILE_MARGIN ) * TILE_ROWS local t = ( TILE_ROWS + 1 ) * 2000 alien.transition = transition.to( alien, {y=target_y, time=t, onComplete=remove_alien} ) alien_group:insert( alien ) table.insert( alien_array, alien ) end local function hit_test( x, y, bounds ) if x > bounds.xMin and x < bounds.xMax and y > bounds.yMin and y < bounds.yMax then return true else return false end end local function hit_test_bounds( bounds1, bounds2 ) return bounds1.xMin < bounds2.xMax and bounds1.xMax > bounds2.xMin and bounds1.yMin < bounds2.yMax and bounds1.yMax > bounds2.yMin end local function check_bullets() for b = 1, #bullet_array, 1 do local bullet = bullet_array[b] if b > #bullet_array then return end for a = 1, #alien_array, 1 do local alien = alien_array[a] if hit_test( bullet.x, bullet.y, alien.contentBounds ) then if alien.life > 0 then alien.life = alien.life - 1 else remove_alien( alien ) end remove_bullet( bullet ) break end end end end local function check_enemies() for a = 1, #alien_array, 1 do local alien = alien_array[a] for d = 1, #defense_array, 1 do local defense = defense_array[d] -- Here we're use the new hit_test_bounds() function to check if the defense and alien overlap if hit_test_bounds( alien.contentBounds, defense.contentBounds ) then -- Check for collision remove_defense( defense ) -- Remove this defense on a collision break end end end end local function on_enterframe( event ) check_bullets() check_enemies() end Runtime:addEventListener( "enterFrame", on_enterframe ) make_grid() local alien_timer = timer.performWithDelay( 5300, make_alien, -1 ) local memory_text = display.newText( "Hello", 5, 5, native.systemFont, 16 ) memory_text:setTextColor( 255, 0, 0 ) memory_text.x = display.contentCenterX local monitorMem = function() collectgarbage() local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000 memory_text.text = "Mem:"..collectgarbage("count") .. " tex:".. textMem end Runtime:addEventListener( "enterFrame", monitorMem )