Destroying Aliens with bullets
In the last post I created bullets that fire from a defense at advancing enemies. I still need to check if an enemy is hit, and if so reduce it’s life, and remove it if it has reached 0 life.
I see many example that would use physics for the collision detection for this. I feel that physics may be over kill for what I am doing here. it’s also my guess that using physics would add a lot of processing overhead. Physics also brings up other problems that need to be solved. All in all I physics, in this case will create more problems than it solves. So, I’m going to opt to use a hit test and manage bullets and alien enemies in arrays.
A few notes on code styles. The code is now getting longer and so I decided to make a few style changes to help me keep organized. Constants, these are variables that will not change value. These will be UPPER_CASE. Lua doesn’t have actual constants, I’m using upper case as a reminder.
Hit Test – Bullets vs Aliens
For each bullet fired, I will need to check if that bullet hits an enemy. To determine a hit take the x and y location of the bullet and check if it is inside the bounds of the enemy. The bounds of an object is represented by four values that define the edges of the rectangle surrounding the object. Use display.contentBounds to get the bounds object. This object will have properties of:
- xMin (defines the left edge)
- xMax (defines the right edge)
- yMin (defines the top edge)
- yMax (defines the bottom edge)
To determine if a point, an x and y pair, is within the bounds of an object use an if statement to compare the bounds properties and the x and y of the point. Check if the x value is greater than xMin and less than xMax, while the y value is greater than yMin and less than yMax. Something like this:
if x > bounds.xMin and x < bounds.xMax and y > bounds.yMin and y < bounds.yMax then ... HIT! ... end
Checking for a single hit is simple and straight forward. With multiple bullets and enemies on the screen at the same time the problem is a more complicated. For each bullet we need to check for a hit against each enemy. To organize this, all bullets need to be in an array and all enemies in another array. In the future I may want enemies to attack defenses so, I made an array to hold defenses also.
local defense_array = {} local alien_array = {} local bullet_array = {}
With the bullets in an array and the enemies in another array we can look at each bullet and perform a hit test against each enemy with that bullet.
Making Bullets
I used the same strategy for bullets that was used for other display elements tiles, aliens and defenses. I need a function to make bullets and another to remove them.
BULLET_SPEED
I used a transition to move the bullets up the screen. The time it takes a bullet to move up the screen will vary by the distance the bullet has to travel. To get the bullets to move at a consistent rate I created the variable BULLET_SPEED. This is a “constant”, that is it’s value will NOT change while the program runs. Corona and Lua do not support actual constants, but this is the intent for this variable, so I will use a style to mark it as such.
I set the speed in pixels per millisecond (1/1000 of a second). I decided on a speed of 400 pixels per second. In milliseconds this becomes 1000 / 400.
local BULLET_SPEED = 1000 / 400
To create transition that moves at this constant rate multiply the distance by BULLET_SPEED and set this value as the time of the transition.
Bullets will be black circles, for now.
Here are two functions to make and remove bullets.
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
To detect a hit I need to look at the position of each bullet and alien and apply a hit test each frame. I added an enterFrame event and handler. I also separated the hit test into it’s own function since it might be useful for other purposes in the future. Note the hit test returns true on a hit or false. This way you can place a hit test inside of an if statement, as in the code below:
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 on_enterframe( event ) 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 Runtime:addEventListener( "enterFrame", on_enterframe )
Here’s a full code listing so far.
Continue reading Corona – Tower Defense Game Experiments 5