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
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,
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
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 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.