Collision detection without physics.
A frequent question that comes up in the Corona SDK forums is how to detect when two images on a screen hit each other. This is known as a “Collision”. The ability to determine when two things have bumped into each other is called “Collision Detection”.
Within Corona SDK, being that its an event driven system, we like the idea that we can have the system tell us when things hit each other and we just have to write the code to handle the interaction of the two. This is a cool concept and it works, but . . .
It requires using the Physics engine to do so.
Corona SDK uses a wonderful 2D Box model for physics and that model supports this event driven model and it works well. But if you’re game does not need physics and many apps don’t, like a card game where you move a card to a stack, its kind of silly and wasteful to include the overhead of the physics engine. You don’t need all of those angular momentum floating point mathematics going on in your game.
So how do I detect collisions? I don’t see any API calls to do that?
We really can’t use an event driven model like the physics engine, but there is a very simple method (well there are two) that use other features of Corona SDK, in particular using an “enterFrame” event on the Runtime listener.
Basically we have to write the code that the physics engine is doing for us and it’s not all that complex.
In my personal model, I typically have a table/array of all of my on screen objects and then I have my player’s avatar object.
| Lua | | copy code | | ? |
| 1 | |
| 2 | local objects = {} |
| 3 | for i=1, 20, do |
| 4 | objects[i] = spawnEnemy() -- spawnEnemy creates on display objects and returns it. |
| 5 | end |
| 6 | |
| 7 | local player = display.newImageRect("avatar.png", 64, 64) -- create me. |
| 8 |
At this point we have a table of enemies in the “objects” table and my player object.
For the Runtime enterFrame event, you need a function to process the collision detection.
| Lua | | copy code | | ? |
| 01 | |
| 02 | local function testCollisions() |
| 03 | for i=1, #objects do |
| 04 | if hasCollided(objects[i], player) then |
| 05 | -- do what you need to do if they hit each other |
| 06 | end |
| 07 | end |
| 08 | end |
| 09 | |
| 10 | Runtime:addEventListener("enterFrame", testCollisions) |
| 11 |
So we simply iterate over the list of objects and see if any have hit the player object using a function called hasCollided.
This is a function that you also have to write.
There are two main methods for doing this, one is based on rectangles overlapping each other. The other involves circle testing.
| Lua | | copy code | | ? |
| 01 | |
| 02 | -- rectangle based |
| 03 | local function hasCollided(obj1, obj2) |
| 04 | if obj1 == nil then |
| 05 | return false |
| 06 | end |
| 07 | if obj2 == nil then |
| 08 | return false |
| 09 | end |
| 10 | local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin |
| 11 | local right = obj1.contentBounds.xMin >= obj2.contentBounds.xMin and obj1.contentBounds.xMin <= obj2.contentBounds.xMax |
| 12 | local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin |
| 13 | local down = obj1.contentBounds.yMin >= obj2.contentBounds.yMin and obj1.contentBounds.yMin <= obj2.contentBounds.yMax |
| 14 | return (left or right) and (up or down) |
| 15 | end |
| 16 | |
| 17 | -- circle based |
| 18 | local function hasCollidedCircle(obj1, obj2) |
| 19 | if obj1 == nil then |
| 20 | return false |
| 21 | end |
| 22 | if obj2 == nil then |
| 23 | return false |
| 24 | end |
| 25 | local sqrt = math.sqrt |
| 26 | |
| 27 | local dx = obj1.x - obj2.x; |
| 28 | local dy = obj1.y - obj2.y; |
| 29 | |
| 30 | local distance = sqrt(dx*dx + dy*dy); |
| 31 | local objectSize = (obj2.contentWidth/2) + (obj1.contentWidth/2) |
| 32 | if distance < objectSize then |
| 33 | return true |
| 34 | end |
| 35 | return false |
| 36 | end |
| 37 |
Depending on the shape of your player and objects, you may find that circles work better or rectangles work better. In my game Omniblaster I used both methods depending on the objects. My space ship has rounded shields and my rocks were basically round, and my enemies were basically round, so using the hasCollidedCircle made more sense to use.
When I say rounded, the images have transparency that when using rectangles would cause the objects to hit before they looked like it.
Yet, when I fired my phasers or torpedoes, those graphics fit nicely into rectangles, so using the rectangle hasCollided method was a better choice.
One gotcha that you need to be aware of is that if your processing takes too long, (longer than 1/30th of a second or 1/60th depending on frame rate) then your collision detection will fire again before you finish, so I usually change my collision handler to something like this:
| Lua | | copy code | | ? |
| 01 | |
| 02 | local isCheckingCollisions = false |
| 03 | local function testCollisions |
| 04 | if isCheckingCollisions then |
| 05 | return true |
| 06 | end |
| 07 | isCheckingCollisions = true |
| 08 | for i=1, #objects do |
| 09 | if hasCollided(objects[i], player) then |
| 10 | -- do what you need to do if they hit each other |
| 11 | end |
| 12 | end |
| 13 | isCheckingCollisions = false |
| 14 | return true |
| 15 | end |
| 16 |
This should be a lighter weight collision detection system than the overhead of the physics engine. Though you don’t get filters, being able to define polygon shapes unless you roll you’re own!
Happy coding!


hey rob on the circle detection if you get rid of the sqrt it will speed up the detection. to do this use
if dx*dx + dy*dy < objectSize*objectSize then
Hey great post! I was JUST thinking about rolling my own non-physics collision stuff but your article saved me the trouble! Very nice!
Here is a small suggestion– When looping through the objects. Start at the end and iterate to the beginning instead.
Example:
for i = #objects, 1, -1 do
end
This allows you to remove objects on collision without throwing off the indices.
Great post, i use it in my next game
Rob, this is great and is the type of situation I’m looking at. However, I need to check if one of those items has collided with another of those 20 items. That potentially means 20!, which = 2.4329+e28 collisions I’d be checking for, right (please correct me if I’m wrong)? Would you only recommend this when you know you have a fairly limited amount of collisions you might be checking, or is there a way to make this work efficiently?
Well that certainly seems like a lot, but if you loop through your 20 objects to see if they are colliding with the other that’s only 20×20 checks per frame which should be manageable….
-- do your bizendendendendHi Rob, thanx nice post.
For my case i used obj1 center point
local left = obj1.x = obj2.contentBounds.xMin
local right = obj1.x >= obj2.contentBounds.xMin and obj1.x <= obj2.contentBounds.xMax
local up = obj1.y = obj2.contentBounds.yMin
local down = obj1.y >= obj2.contentBounds.yMin and obj1.y <= obj2.contentBounds.yMax
return (left or right) and (up or down)