This series of posts has been going on for some time. I’m up to 13! I’m not done with the game yet, but it does have some interesting features.
In this post I’d like to add some “explosions”. What I really want is a small animated effect to show that an enemy has been hit by a bullet. For simplicity I’ll stick with the shapes and use a circle for the explosion. This could be replaced in the future.
The strategy here will be the same as was used with everything else, use factory function to create objects, and another function to remove the object when the explosion is finished.
Explosions will be animated with a transition animating the width and height. The onComplete will be used to remove the explosion when the animation finished.
-- Use this function to remove explosions local function remove_explosion( explosion ) display.remove( explosion ) end -- Use this function to make explosions local function make_explosion( x, y ) local explosion = display.newCircle( 0, 0, 1 ) explosion.x = x explosion.y = y explosion:setFillColor( 0, 0, 255, 66 ) explosion.strokeWidth = 3 explosion:setStrokeColor( 0, 0, 255, 128 ) alien_group:insert( explosion ) transition.to( explosion, {width=20, height=20, time=500, onComplete=remove_explosion} ) end
Above are the two functions. These are pretty simple. I made the explosions blue to separate them from the enemies (green), and the defenses (red).
The explosion is added to the alien_group. This keeps them inside the game_group, since alien_group is a child of game_group, and should keep new explosions on top of existing enemies.
All that’s need now is to call make_explosion( x, y ) and pass the x and y location where the explosion should occur. Bullets hit enemies in the check_bullets() function.
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 make_explosion( alien.x, alien.y ) -- Add an explosion on a hit alien.life = alien.life - bullet.damage local defense_name = bullet.defense_name if defense_name == "Stun" then transition.cancel( alien.transition ) local t = ( alien_target_y - alien.y ) * ALIEN_SPEED alien.transition = transition.to( alien, { y=alien_target_y, time=t, delay=300, onComplete=remove_alien } ) end else remove_alien( alien ) end remove_bullet( bullet ) break end end end end
Find the comment in the function above. Here you can see a call to make_explosion( alien.x, alien.y ). This creates a new explosion at the location of the enemy. You might have also placed the explosion at the location of the bullet instead.
Here’s full listing:
----------------------------------------------------------------------------------------- -- -- main.lua -- ----------------------------------------------------------------------------------------- -- This example added a small explosion when a bullet hits an enemy 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 ALIEN_SPEED = 1000 / 20 local ENERGY_RECHARGE_RATE = 1 local ENERGY_TIMER_TIME = 150 local alien_timer local energy_timer local energy = 0 local current_defense_type = 1 local energy_text local alien_target_y = ( TILE_SIZE + TILE_MARGIN ) * TILE_ROWS local defense_array = {} local alien_array = {} local bullet_array = {} local defense_type_array = { {name="Standard", rof=1000, damage=1, cost=50}, {name="Rapid", rof=800, damage=1, cost=75}, {name="Heavy", rof=2000, damage=3, cost=100}, {name="Stun", rof=1200, damage=0.5, cost=80} } local alien_type_array = { { name="normal", speed=ALIEN_SPEED, life=5, green=200 }, { name="fast", speed=ALIEN_SPEED / 2, life=2, green=255 }, { name="slow", speed=ALIEN_SPEED * 2, life=10, green=165 }} local defense_button_array = {} local game_group = display.newGroup() local defense_group = display.newGroup() local alien_group = display.newGroup() local tile_group = display.newGroup() local control_group = display.newGroup() game_group:insert( tile_group ) game_group:insert( defense_group ) game_group:insert( alien_group ) local function select_defense_button() for i = 1, #defense_button_array, 1 do local button = defense_button_array[i] if button.index == current_defense_type then button.shape.strokeWidth = 3 else button.shape.strokeWidth = 0 end end end local function enable_disable_buttons() for i = 1, #defense_button_array,1 do local button = defense_button_array[i] local cost = button.cost if cost < energy then button.enabled = true button.alpha = 1.0 else button.enabled = false button.alpha = 0.5 end end end local function touch_defense_button( event ) local button = event.target current_defense_type = button.index select_defense_button() end local function make_defense_buttons() for i = 1, #defense_type_array, 1 do local button_group = display.newGroup() local button = display.newRoundedRect( 0, 0, 40, 40, 6 ) local r = 255 * ( i / #defense_type_array ) button:setFillColor( r, 0, 0 ) button:setStrokeColor( 255, 255, 255 ) defense_type_array[i].red = r button_group.cost = defense_type_array[i].cost button_group.enabled = false local button_text = display.newText( "0", 0, 0, native.systemFontBold, 14 ) button_text.text = defense_type_array[i].cost button_text.x = 20 button_text.y = 30 -- Add a name label to each button local button_name_text = display.newText( "", 0, 0, native.systemFont, 12 ) button_name_text.text = defense_type_array[i].name button_name_text.x = 20 button_name_text.y = 10 button_group:insert( button ) button_group:insert( button_text ) button_group:insert( button_name_text ) -- insert button into group button_group.shape = button button_group.label = button_text button_group.index = i button_group.x = display.contentWidth - 45 button_group.y = 40 + ( i * 50 ) button_group:addEventListener( "touch", touch_defense_button ) table.insert(defense_button_array, button_group ) control_group:insert( button_group ) end end make_defense_buttons() select_defense_button() enable_disable_buttons() energy_text = display.newText( energy, 0, 0, native.systemFont, 16 ) control_group:insert( energy_text ) energy_text:setTextColor( 0, 255, 0 ) energy_text.x = 300 energy_text.y = 40 local function update_energy() energy_text.text = energy end local function energy_recharge() energy = energy + ENERGY_RECHARGE_RATE enable_disable_buttons() update_energy() end energy_timer = timer.performWithDelay( ENERGY_TIMER_TIME, energy_recharge, -1 ) -- Use this function to remove explosions local function remove_explosion( explosion ) display.remove( explosion ) end -- Use this function to make explosions local function make_explosion( x, y ) local explosion = display.newCircle( 0, 0, 1 ) explosion.x = x explosion.y = y explosion:setFillColor( 0, 0, 255, 66 ) explosion.strokeWidth = 3 explosion:setStrokeColor( 0, 0, 255, 128 ) alien_group:insert( explosion ) transition.to( explosion, {width=20, height=20, time=500, onComplete=remove_explosion} ) end 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} ) return 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 local bullet = make_bullet( defense.x, defense.y ) bullet.damage = defense.damage bullet.defense_name = defense.defense_name break end end end local function remove_defense( defense ) local index = table.indexOf( defense_array, defense ) timer.cancel( defense.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.rof = defense_type_array[current_defense_type].rof defense.damage = defense_type_array[current_defense_type].damage defense.defense_name = defense_type_array[current_defense_type].name defense.red = defense_type_array[current_defense_type].red defense:setFillColor( defense.red, 0, 0 ) defense_group:insert( defense ) defense.x = x defense.y = y table.insert( defense_array, defense ) defense.timer = timer.performWithDelay( defense.rof, 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 cost = defense_type_array[current_defense_type].cost if energy >= cost then energy = energy - cost local defense = make_defense( tile_x, tile_y ) defense.col = tile.col end 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_type = alien_type_array[ math.random( 1, #alien_type_array ) ] local alien = display.newRect( 0, 0, 32, 32 ) alien.alien_type = alien_type alien:setFillColor( 0, alien_type.green, 0 ) local col = math.random( 1, TILE_COLS ) alien.col = col alien.x = col * ( TILE_SIZE + TILE_MARGIN ) alien.y = 0 alien.life = alien_type.life local t = alien_target_y * alien_type.speed alien.transition = transition.to( alien, {y=alien_target_y, time=t, onComplete=remove_alien} ) alien_group:insert( alien ) table.insert( alien_array, alien ) end local function hit_test( x, y, bounds ) return x > bounds.xMin and x < bounds.xMax and y > bounds.yMin and y < bounds.yMax 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 make_explosion( alien.x, alien.y ) -- Add an explosion on a hit alien.life = alien.life - bullet.damage local defense_name = bullet.defense_name if defense_name == "Stun" then transition.cancel( alien.transition ) local t = ( alien_target_y - alien.y ) * ALIEN_SPEED alien.transition = transition.to( alien, { y=alien_target_y, time=t, delay=300, onComplete=remove_alien } ) end 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] if hit_test_bounds( alien.contentBounds, defense.contentBounds ) then remove_defense( defense ) break end end end end local function on_enterframe( event ) check_bullets() check_enemies() end Runtime:addEventListener( "enterFrame", on_enterframe ) make_grid() 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 = math.round( system.getInfo( "textureMemoryUsed" ) / 1000000 ) memory_text.text = "Mem:"..math.round( collectgarbage("count")) .. " tex:".. textMem end Runtime:addEventListener( "enterFrame", monitorMem )