Corona includes a robust
There are a few ways to detect collisions without using physics, including:
The first method can be complex if the rectangle has any rotation applied to it, and the separating axis theorem is fairly
Before considering
In some games, even objects that aren’t artistically circular can often have their collision boundaries represented by a circle, for instance a circle that encloses the entire image or alternatively spans a slightly smaller area around the “center” of the object. During fast gameplay, the player probably won’t notice exact
Some very simple calculations can determine if any two circles of arbitrary sizes are overlapping:
local function hasCollidedCircle( obj1, obj2 ) if ( obj1 == nil ) then -- Make sure the first object exists return false end if ( obj2 == nil ) then -- Make sure the other object exists return false end local dx = obj1.x - obj2.x local dy = obj1.y - obj2.y local distance = math.sqrt( dx*dx + dy*dy ) local objectSize = (obj2.contentWidth/2) + (obj1.contentWidth/2) if ( distance < objectSize ) then return true end return false end
For this function, we simply pass in two display objects, obj1
and obj2
. Using the contentWidth
property to determine their width, we check if the two circles are closer than the distance of their centers and, if so, we know that they’re touching.
Overlapping rectangles are even easier to detect, using Corona’s contentBounds
properties:
local function hasCollidedRect( obj1, obj2 ) if ( obj1 == nil ) then -- Make sure the first object exists return false end if ( obj2 == nil ) then -- Make sure the other object exists return false end local left = obj1.contentBounds.xMin <= obj2.contentBounds.xMin and obj1.contentBounds.xMax >= obj2.contentBounds.xMin local right = obj1.contentBounds.xMin >= obj2.contentBounds.xMin and obj1.contentBounds.xMin <= obj2.contentBounds.xMax local up = obj1.contentBounds.yMin <= obj2.contentBounds.yMin and obj1.contentBounds.yMax >= obj2.contentBounds.yMin local down = obj1.contentBounds.yMin >= obj2.contentBounds.yMin and obj1.contentBounds.yMin <= obj2.contentBounds.yMax return ( left or right ) and ( up or down ) end
This function works great for square or rectangular objects like tiles and cards. It uses a set of if
statement checks to see if any corner of one rectangle is inside the bounds of the other rectangle.
For images that have some transparency around them, note that this will include the transparent areas since the function uses the content bounds of those images. If necessary, you can adjust the math in the comparisons, for instance add or subtract a pixel value to/from the various “min” and “max” properties to account for the width of the transparency.
Now that you have a couple different ways to determine if two items have collided, how can you use them? Unlike
Perhaps the most obvious method is to use an "enterFrame"
Runtime listener as follows:
As a
As a listener method which you toggle on and off as needed, for example only when the player is
Consider this example function which assumes that you have a myPlayer
object and multiple coin objects stored in a table named coinCache
. Assuming the player can also use coinCache
table on each frame and checks if the player has come into contact with any coins:
local function gameLoop( event ) for i = 1,#coinCache do -- Check for collision between player and this coin instance if ( coinCache[i] and hasCollidedCircle( myPlayer, coinCache[i] ) ) then -- Remove the coin from the screen display.remove( coinCache[i] ) -- Remove reference from table coinCache[i] = nil -- Handle other collision aspects like increasing score, etc. end end return true end Runtime:addEventListener( "enterFrame", gameLoop )
That concludes our tutorial on
Character art in this tutorial is courtesy of Kenney. Kenney game studio supports other developers by creating free game assets and high quality learning material.