Share Your Code

Flash's hitTestObject() emulated using contentBounds

Posted by jhocking, Posted on January 21, 2011, Last updated March 22, 2012

You call this function with two images. It returns true if the images are overlapping, and false if they aren't. This is pretty handy for basic collision detection without using physics.

1
2
3
4
5
6
function hitTestObjects(obj1, obj2)
        return obj1.contentBounds.xMin < obj2.contentBounds.xMax
                and obj1.contentBounds.xMax > obj2.contentBounds.xMin
                and obj1.contentBounds.yMin < obj2.contentBounds.yMax
                and obj1.contentBounds.yMax > obj2.contentBounds.yMin
end

Here's a sample demonstrating the function (paste the function above this code.) Drag around the square in the corner and the terminal output says whether or not the two squares are overlapping.

1
2
3
4
5
6
7
8
9
10
local img1 = display.newRect(0, 0, 50, 50)
local img2 = display.newRect(100, 100, 50, 50)
local function drag(event)
        if event.phase == "moved" then
                img1.x = event.x
                img1.y = event.y
                print(hitTestObjects(img1, img2))
        end
end
img1:addEventListener("touch", drag)

Note: as alluded to above, this function is really only useful if you aren't using physics. If you are, then use the collision functions provided by the physics engine.

Compatibility: 
Corona 2.0

Replies

AlexGreene
User offline. Last seen 2 years 5 weeks ago. Offline
Joined: 18 Jun 2010

This is great! Thanks!

luna
User offline. Last seen 1 year 12 weeks ago. Offline
Joined: 4 Aug 2010

This works and works well. It worked out of the box. Thanks for sharing.

EdwardK
User offline. Last seen 2 years 47 weeks ago. Offline
Joined: 15 Dec 2010

Thanks for sharing. Use this all over the place but:
collision happens before they touch.
add to your example above:

1
2
3
4
5
6
7
8
physics.addBody( img1, "dynamic", { bounce = 0 , density = 2, friction=0.7, isSensor=true} )--
physics.addBody( img2, "dynamic", { bounce = 0 , density = 2, friction=0.7} )--
local function collide(event)
   if event.phase == "began" then
      print ("COLLIDING")
   end
end
img1:addEventListener("collision", collide)

Watch the COLLIDING happen inside "falses" as you move the shapes close to each other.
Had to add a tolerance of 1 to make hitTest and collision the same.

jhocking
User offline. Last seen 1 year 37 weeks ago. Offline
Joined: 4 Dec 2010

That's an interesting observation so thanks, but if you are using physics then you shouldn't need my hitTest function. I guess I'll specify this in the description, but my function is really only intended for games without physics.

FrankS
User offline. Last seen 2 years 50 weeks ago. Offline
Joined: 7 Aug 2010

Nice - should be part of Corona's core API.

-FrankS.

walter
User offline. Last seen 1 week 5 days ago. Offline
Staff
Joined: 22 Jun 2009

@FrankS, what's the use case for hit-testing outside a touch?

FrankS
User offline. Last seen 2 years 50 weeks ago. Offline
Joined: 7 Aug 2010

I've modified Gilbert's TableView library to allow for a more generic scrolling and use this hit-testing to see if the scrolling-group will hit the objects that determine the scrolling boundary or if the scrolling-group came free from the boundary object.

Because the different groups and objects live in different coordinate systems, this function will make it easy to do a does/does-not overlap test.

-FrankS.

writetoamrutha
User offline. Last seen 3 years 5 weeks ago. Offline
Joined: 11 Mar 2011

Hey this is really good but can you please tell me how to use the result of the function. As in when the function returns true I want the obj1 and obj2 to be removed and score incremented. Please let me know. Cause when I do it now either Corona crashes or the objects get removed before on tap itself.

jhocking
User offline. Last seen 1 year 37 weeks ago. Offline
Joined: 4 Dec 2010

Well your question isn't specific to this function so you should ask it on the forum. Also, you apparently have code that is crashing so you should ask about that (ie. here's my code, why is it crashing?) And explain more fully what you are doing, because at the end you mention tapping but it's not clear what the user is tapping on.

coderebelbase
User offline. Last seen 1 year 11 weeks ago. Offline
Joined: 1 Feb 2010

wrong page

finefin
User offline. Last seen 1 year 41 weeks ago. Offline
Joined: 14 Jun 2011

Hi all
I found out about Corona yesterday and today I scripted my first game, a simple shoot em up.

Many bullets, many enemies. I needed easy collision testing.
So I found this snippet here that seemed to work well in the beginning.

But this method is quite performance heavy if you hitTest many objects on each other.

so, if your objects are round(ish) you should do what jayantv suggested here: http://developer.anscamobile.com/forum/2010/10/29/collision-detection-without-physics#comment-9538

this is what I've done with this knowledge:

1
2
3
4
5
6
7
8
9
10
11
function hitTestObjects(obj1, obj2)
                local sqrt = math.sqrt
                local dx =  obj1.x - obj2.x
                local dy =  obj1.y - obj2.y
                local distance = sqrt(dx*dx + dy*dy)
                if distance < 50 then -- 50px radius
                return true
                else
                return false
                end
end

Three cheers to Pythagoras!

jhocking
User offline. Last seen 1 year 37 weeks ago. Offline
Joined: 4 Dec 2010

Maybe I'll add that function to my top post named hitTestRadius. And I'll add a parameter for the distance value, so it'll be hitTestRadius(obj1, obj2, dist)

Although, it's probably better to use the distanceBetween function from here because that give you more flexibility in what to do with that number:

http://developer.anscamobile.com/forum/2010/11/17/math-helper-functions-distancebetween-and-anglebetween

ChunkyApps
User offline. Last seen 2 days 2 hours ago. Offline
Joined: 19 Jan 2011

Awesome stuff... just what I was looking for!

edaabs
User offline. Last seen 32 weeks 12 hours ago. Offline
Joined: 28 Jul 2011

This seems like the method I am looking for, only I am using sprites from a spritesheet instead of rectangular display objects, and am getting errors in the simulator instead of the true/false readouts the sample code delivers. I'm currently just substituting the img1 and img2 variables with my sprite names. Can this method be tweaked to work with sprites, or can it only work with rectangles?

As an alternative, I'm considering creating invisible rectangles over-top of each one of my sprites as a possible work-around.

jhocking
User offline. Last seen 1 year 37 weeks ago. Offline
Joined: 4 Dec 2010

I just realized a way to do this using 4 comparisons instead of 8, so that should make this function more efficient.

Minion Multimiedia
User offline. Last seen 2 weeks 23 hours ago. Offline
Joined: 19 Oct 2010

Thanks!!!