AS 3.0 HitTest

Recently I’ve needed some shape based hit detection in As 3.0 so as a starting point I decided to convert Grant’s CollisionDetection class. I’ve split the code out into 3 methods and optimized it a bit by creating a BitmapData as small as possible .

Here’s a description and example of each of the methods.

ComplexHitTestObject

HitTest.complexHitTestObject( target1:DisplayObject, target2:DisplayObject, accuracy:Number );

ComplexHitTestObject example

Returns a Boolean depending on whether the 2 DisplayObjects passed as parameters are overlapping each other. The 3rd parameter specifies how accurate the test it. The higher the number, the greater the size the BitmapData is drawn internally, and therefore the scale at which the 2 DisplayObjects are drawn onto the BitmapData. The default for the accuracy parameter is 1. If you try and pass a value of 0 or less the method will thorw an error.

IntersectionRectangle

HitTest.intersectionRectangle( target1:DisplayObject, target2:DisplayObject );

IntersectionRectangle example

Returns a Rectangle matching the co-ordinates where the boundaries of the 2 DisplayObjects passed as parameters overlap. This method does a simple test much like hitTestObject().

ComplexIntersectionRectangle

HitTest.complexIntersectionRectangle( target1:DisplayObject, target2:DisplayObject, accuracy:Number );

ComplexIntersectionRectangle example

Returns a Rectangle matching the co-ordinates where the 2 DisplayObjects passed as parameters overlap. The 3rd parameter specifies how accurate the test it. The higher the number, the greater the size the BitmapData is drawn internally, and therefore the scale at which the 2 DisplayObjects are drawn onto the BitmapData. The default for the accuracy parameter is 1. If you try and pass a value of 0 or less the method will thorw an error.

You can view the source in any of the examples above by right clicking and selecting ‘View source’. Each include the HitTest class, also included below.

package ws.tink.display
{
 
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
 
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
 
	public class HitTest
	{
 
		public static function complexHitTestObject( target1:DisplayObject, target2:DisplayObject,  accurracy:Number = 1 ):Boolean
		{
			return complexIntersectionRectangle( target1, target2, accurracy ).width != 0;
		}
 
		public static function intersectionRectangle( target1:DisplayObject, target2:DisplayObject ):Rectangle
		{
			// If either of the items don't have a reference to stage, then they are not in a display list
			// or if a simple hitTestObject is false, they cannot be intersecting.
			if( !target1.root || !target2.root || !target1.hitTestObject( target2 ) ) return new Rectangle();
 
			// Get the bounds of each DisplayObject.
			var bounds1:Rectangle = target1.getBounds( target1.root );
			var bounds2:Rectangle = target2.getBounds( target2.root );
 
			// Determine test area boundaries.
			var intersection:Rectangle = new Rectangle();
			intersection.x 		= Math.max( bounds1.x, bounds2.x );
			intersection.y		= Math.max( bounds1.y, bounds2.y );
			intersection.width 	= Math.min( ( bounds1.x + bounds1.width ) - intersection.x, ( bounds2.x + bounds2.width ) - intersection.x );
			intersection.height = Math.min( ( bounds1.y + bounds1.height ) - intersection.y, ( bounds2.y + bounds2.height ) - intersection.y );
 
			return intersection;
		}
 
		public static function complexIntersectionRectangle( target1:DisplayObject, target2:DisplayObject, accurracy:Number = 1 ):Rectangle
		{			
			if( accurracy < = 0 ) throw new Error( "ArgumentError: Error #5001: Invalid value for accurracy", 5001 );
 
			// If a simple hitTestObject is false, they cannot be intersecting.
			if( !target1.hitTestObject( target2 ) ) return new Rectangle();
 
			var hitRectangle:Rectangle = intersectionRectangle( target1, target2 );
			// If their boundaries are no interesecting, they cannot be intersecting.
			if( hitRectangle.width * accurracy < 1 || hitRectangle.height * accurracy < 1 ) return new Rectangle();
 
			var bitmapData:BitmapData = new BitmapData( hitRectangle.width * accurracy, hitRectangle.height * accurracy, false, 0x000000 );	
 
			// Draw the first target.
			bitmapData.draw( target1, HitTest.getDrawMatrix( target1, hitRectangle, accurracy ), new ColorTransform( 1, 1, 1, 1, 255, -255, -255, 255 ) );
			// Overlay the second target.
			bitmapData.draw( target2, HitTest.getDrawMatrix( target2, hitRectangle, accurracy ), new ColorTransform( 1, 1, 1, 1, 255, 255, 255, 255 ), BlendMode.DIFFERENCE );
 
			// Find the intersection.
			var intersection:Rectangle = bitmapData.getColorBoundsRect( 0xFFFFFFFF,0xFF00FFFF );
 
			bitmapData.dispose();
 
			// Alter width and positions to compensate for accurracy
			if( accurracy != 1 )
			{
				intersection.x /= accurracy;
				intersection.y /= accurracy;
				intersection.width /= accurracy;
				intersection.height /= accurracy;
			}
 
			intersection.x += hitRectangle.x;
			intersection.y += hitRectangle.y;
 
			return intersection;
		}
 
 
		protected static function getDrawMatrix( target:DisplayObject, hitRectangle:Rectangle, accurracy:Number ):Matrix
		{
			var localToGlobal:Point;;
			var matrix:Matrix;
 
			var rootConcatenatedMatrix:Matrix = target.root.transform.concatenatedMatrix;
 
			localToGlobal = target.localToGlobal( new Point( ) );
			matrix = target.transform.concatenatedMatrix;
			matrix.tx = localToGlobal.x - hitRectangle.x;
			matrix.ty = localToGlobal.y - hitRectangle.y;
 
			matrix.a = matrix.a / rootConcatenatedMatrix.a;
			matrix.d = matrix.d / rootConcatenatedMatrix.d;
			if( accurracy != 1 ) matrix.scale( accurracy, accurracy );
 
			return matrix;
		}
 
	}
 
}

116 Responses to “AS 3.0 HitTest”

  1. DUDE!!! This is sweet! Thanks for posting!

    Cheers,
    Sam

  2. ArneOb says:

    Great! But: in addition to this I wonder if someone found a 100% working solution for dragged objects leaving the stage bounds. In your examples the circle may disappear and never seen again.

    Grüße
    _____
    Arne

  3. [...] Home About Tink » Blog Archive » AS 3.0 HitTest Tink » Blog Archive » AS 3.0 HitTest June 25th, 2007 Lea [...]

  4. Benny says:

    Thanks. Very handy.

    But when try to view the source, I’m taken to http://intlstore.mozilla.org

  5. Tink says:

    @Arne

    You can do this easily in AS 3.0 by adding a listener to the Stage object.

    stage.addEventListener( MouseEvent.MOUSE_LEAVE, onStageMouseLeave ):

  6. Benny says:

    Thanks for the links. The view source seems to be working fine now. Dumping my cache seemed to sort it. Using firefox 1.8.1.4 on a mac…

  7. [...] f Grant Skinner’s Collision Detection class in AS 3.0. Good stuff, have a look see. This entry was posted on Monday, June 25th, 2007 a [...]

  8. swearingen says:

    greetings,

    wondering if you have any examples of the hit test using AS3 and something
    like a maze ?

    peace!

  9. Tink says:

    @ swearingen

    nope, have you gave it a go?

  10. swearingen says:

    no, I’m afraid it’s above me (for now) …

  11. Glenn says:

    Please forgive this newbie for being so stupid, but I don’t know how to get this into a .fla file and get it to work. Is there no .fla file? Or can you post a link to ComplexHitTestObject.fla? I’m afraid to come back here and read the comments ;-o

  12. Jonas Funk says:

    Thank you! Saved me alot of headakes compared to the cryptic BitmapData.hittest(). Very easy to use.

    /Jonas

  13. Martin says:

    Hi,

    will this work for rotated objects? Rotated display objects in flex will leave a transparent box behind. Are these treated accordingly?

  14. Tink says:

    This should work for any shapes at any rotation. I’ve not tested them in Flex it was original put together for a car game.

    I not sure what you mean by display objects leave transparent boxes behind. Can you describe a user case so I understand what you mean little more.

  15. Tink says:

    @ Glen

    sorry for such a sloooow reply I missed this one. You need to have a look into using external classes. You should find lots of info on using the Document Class in Flash 9, that would be a good start.

  16. Martin says:

    Hi Tink,

    Actually I tested it with rotated objects and it worked. The accuracy has to be around 6 or more.

    However it seemed that it was a bit slow. What’s the best accuracy value to use to strike a balance between efficiency and accuracy?

    By the transparent box I mean that taking the example of a rectangle being rotated at 45 degrees it still is a rectangle. Images rotated in flex always rotate around a rectangle. For example even the hitTestObject of AS doesn’t work properly when 2 rotated objects at 45 collided. you will notice that one moving towards the other will hit the “transparent” area.
    I don’t know how to explain correctly hope you meant what I mean. but no problem you’r seem to really take care of it.

    Thanks again! You saved me a lot of work. The hitTest out there don’t really work and most of them told me they were never tested with rotated objects. but this one works. Amazingly enough you didn’t use the hitTest method of the BitmapData class.

  17. Tink says:

    Right your talking about the bounding box, there isn’t actually a transparent rectangle there.

    Generally I would go with using an accuracy of 1. This means all objects are drawn at their actual size.

  18. Aneurin says:

    I used these classes in a small game I recently developed in my own time, after swearing for days searching for a solution to the lack of accurate collision detection in AS3. (I still cannot believe there is no function to do this in 3, when hitTest() in AS2 could do it!)

    Anyway, I really appreciate your work on this – saved me a lot of headaches. And if you want to try the game for yourself, have a link! ;]

    games.aneuri.net/paperplane

  19. Tink says:

    Hey Aneurin

    The game was pretty cool. Cheers!

  20. iSc00t says:

    Hello Tink,

    This seems like some very nice coding indeed. Been looking for some decent hitTest stuff.

    Is it possible to get this code working for non-sprite objects? (like flash movieclips of more complex shapes).

    I saw in Aneurin that this seem to be at work, but with all I’ve tried i cant seem to get to work. I’m still a bit new to AS3 so that may be why…

    Ether way thanks for sharing your hard work!

  21. Tink says:

    @ iSc00t

    It should work with any kind of DisplayObject (i.e. anything you can put in a display list and see on screen).

    If you having it working with Sprite’s it should work in exactly the same way with other DisplayObjects.

  22. iSc00t says:

    @ Tink

    Got it working good now (had a silly order mistake). Thank you very much again!

    If I get this project up and running I’ll send you a link and give you credit for the coding if you want it.

  23. Tink says:

    Hey iSc00t

    I’d love to see a link for the finished project, but don’t worry about a link. I would suggest you use the version in our new code repository and that has a license added to the code.

    http://code.google.com/p/tink/

  24. [...] やっとビットマップの中に入れたーっとちょっと喜んでます。 http://www.tink.ws/blog/as-30-hittest/ の HitTest と http://d.hatena.ne.jp/nitoyon/20071002/potrace の [...]

  25. john says:

    hi Tink,
    will u marry me?

    love,

    john.

  26. Joshua M says:

    Thanks for the great script! It was critical for a flash heatmap app I am building. I’ll be sure to mention the props in the source – and hopefully i’ll remember to link you to it once it’s done

  27. Aaron says:

    Having a bit of trouble with the hit test working from a loaded SWF. What I mean by that is i created a game which uses the your hit test. Works fantastic. Once I load that game SWF into another SWF though, the hit test just won’t work. Best I can figure is it has something to do with all the “root” references in the class. I’ve tried a hundred different things but still can’t get it to work. Any ideas?

  28. Aaron says:

    Update to my previous comment. Loading the SWF into the main display list of another SWF works, but loading it into the display list of a movieclip which sits on the main stage won’t work.

  29. Tink says:

    Hey Aaron

    I have come across this problem before, and I’m pretty sure its the following lines.

    var rootConcatenatedMatrix:Matrix = target.root.transform.concatenatedMatrix;

    matrix.a = matrix.a / rootConcatenatedMatrix.a;
    matrix.d = matrix.d / rootConcatenatedMatrix.d;

    To confirm this can you see if you get a different value for

    target.root.transform.concatenatedMatrix

    in the situation where it doesn’t work correctly?

  30. Aaron says:

    Yes, I do get a different value, but only for tx and ty. In the single SWF instance I get (a=1, b=0, c=0, d=1, tx=0, ty=0). Loading the game SWF into a movieclip sitting on the main stage of the second SWF I get (a=1, b=0, c=0, d=1, tx=512, ty=384), tx and ty reporting the original SWF’s location relative to the second SWF’s main stage(in the middle of the stage).

    I learned something more though. Importing the game SWF into the main stage of the second SWF works (which we knew), unless you reposition it. As long as the game SWF resides at 0,0 the game functions. Reposition it though and the hit test no longer works. I’m sure you noticed this as well but just in case I figured I would put it out there.

    In all possible versions that I’ve tried out (single SWF, double SWF main stage, double SWF movieclip, etc.), they all report back a=1, b=0, c=0, d=1 but tx and ty are the only things that change. Let me know if this helps or if you have any other questions. I’m very interested in seeing if we can get this to work. Thanks again.

  31. Tink says:

    do you think you could mock up a very simple example (maybe just circles that hit like the examples above), and then send it me, so I can see if i can resolve the problem.

    You can get me at blogATtink.ws

  32. [...] ;     return matrix;         }     } } 原地址http://www.tink.ws/blog/as-30-hittest/ 相关文 flash as3的文字描边效果 [...]

  33. Savage says:

    Nice work, but if one of the DisplayObjects is masked (mc1.mask = mymask;), the complexHitTestObject returns also true. I mean, if the one objects is partially hidden and I move with another object on these hidden elements, complexHitTestObject returns true… I hope you know what I mean and can give me an solution? :)

  34. Anthony says:

    Thanks Tink,
    The hitTestObject method wasn’t working for me when i wanted to compare label positions ( so that i would not get label overlaps on a map ) it returned true but not until the labels were very very far apart!.
    This sorted it
    Thanks

  35. vitaLee says:

    any solution to this addChild/position problem?

  36. sultan says:

    Great Class! Saved me loads of time man! THX

  37. musa says:

    Thanks Tink,
    It’s very useful, ;)

  38. Patrick says:

    for people in search for a solution in particle system (like 500 Objects) I recommend:

    private function hitTest(point:DisplayObject):Boolean{

    var pt1:Point = new Point(impactZone.x, 300);
    var pt2:Point = new Point(point.x,point.y);
    return impactZone.bitmapData.hitTest(pt1, 0xFF, pt2);
    }
    (impactZone is a bitmap ).
    It`s very fast if you can live with only a point check.
    regards Patrick

  39. michael says:

    Hi Tink, thanks for the great class.

    I am having the same problem as Aaron with the collision detection not working in a swf loaded into a larger swf (but working fine in a single swf). I was able to resolve the problem with the in built hitTestPoint method by using localToGlobal on the point, but i’m not sure how to employ a similar solution with a display object.

    Did you or Aaron resolve the problem using your class? Would love to know a solution.

    Many thanks

    Michael

  40. Aaron says:

    I never did find a solution and had to end up putting everything in one SWF.

  41. Tink says:

    I had the above problems in the project I originally ported this for and as I remember the error was due to a change in the values on rootConcatenatedMatrix.

    To solve it I remember finding the difference between the value when it was running in it’s own SWF, and when it was loaded into another, and just mutiplied the values to compensate.

    This was at a very early stage in the release of Flash Player 9, and whilst testing the project I found that the change in rootConcatenatedMatrix could be different each time I tested.

    If this is the case can you please confirm by posting here.

  42. michael says:

    Hi Tink, thanks for the reply.

    I agree, I think this is exactly what’s happening. If I do a hitTestPoint I can trace out the difference and fix it with a root.localToGlobal

    I just don’t know how to, or where to add the difference in the more complex hitText.

    I’m using Flash Player 10 and I am actively checking for version 9.0.28 so i’m not sure if that would be an issue.

    Thanks for your assistance mate

  43. Tink says:

    its these lines you’d have to amend

    matrix.a = matrix.a / rootConcatenatedMatrix.a;
    matrix.d = matrix.d / rootConcatenatedMatrix.d;

    check the diff between rootConcatenatedMatrix.a and rootConcatenatedMatrix.d, when running in its own SWF of loaded into another, and then multiply or divide to normalize the values to what they would be when running inside their own SWF.

  44. michael says:

    Tink,

    Mate! thanks for your help. Got it working. It was actually the matrix.tx and ty values (which makes sense now I think about it). I have put in a very quick and dirty amendment but when I get time after the project is finished i’ll clean it up and send it to you if your interested … but this is essentially what i’ve done.

    if(ConsoleSettings.OFFSET_STAGE){
    matrix.tx = matrix.tx – ConsoleSettings.TX_OFFSET;
    matrix.ty = matrix.ty – ConsoleSettings.TY_OFFSET;
    }

    ConsoleSetting is obviously my class where I keep all my console settings (hmmm).

    Thanks again mate, if you’re ever in Melbourne ping me an e-mail and i’ll buy you a beer.

    Michael

  45. Martin says:

    I think I found a weird bug…

    the collision works when an object moves… however there is this funny situation that when two objects are collided .. sometimes the complexHitTestObject returns true and sometimes false (when both objects are not moving)

    why is this?

  46. [...] onclick=”javascript:pageTracker._trackPageview(‘/outgoing/www.tink.ws/blog/as-30-hittest/’);” href=”http://www.tink.ws/blog/as-30-hittest/”>http://www.tink.ws/blog/as-30-hittest/ の HitTest と http://d.hatena.ne.jp/nitoyon/20071002/potrace の [...]

  47. corbanb says:

    @tink @aaron did you guys ever decide on a fix for this hitTest issue when loaded into another SWF and not set to 0,0?

    Looks like Micheal fixed it but I’m not sure how I can implement it. Is there a way we can do this instead the Class itself or what are the options?

  48. corbanb says:

    well I got it working for me! I guess I spoke a little prematurely. Its not a flexible fix but it does the trick. all that needs to be added is.

    matrix.tx = matrix.tx – (250); //set to the x-cords of the game
    matrix.ty = matrix.ty – (250); //set to the y-cords of the game

    where the 250′s are where the SWF is being loaded. So this will have to change. but its a HACK for it to work quickly. Cheers!

  49. dimebagplan says:

    Tink, thanks for share this awesome class !
    The test i have done works like a charm !

    The hitTest of the bitmap Data Class was really horrible to use.

    For now i have tested with some png, and even when the objects are rotating, it works perfectly !

    Thanks again !

    Dimebagplan.

  50. dimebagplan says:

    oops, sorry for double post, i have also the same problem as Aaron and Michael…

    When i load it from a swf.
    The collision don’t work anymore.

    Do you know how to fix it ?

    Thanks.

  51. Tink says:

    see corbanb’s solution above

  52. [...] っていましたが 下記の手法では、画像単位で取れるようになりました。 http://www.tink.ws/blog/as-30-hittest/ 最近、仕事も多いので、誰か手伝ってく さい! Today, 11:35 AM Leave a rep [...]

  53. [...]

    Hier is een klasse voor op de pixel hittest Tink Blog Archive AS 3.0 HitTest

    __________________
    [...]

  54. summer says:

    thank you! worked flawless and saved me some time!

  55. Horous says:

    Hi Tink !
    Thanks for this amazing work…
    I’m trying to check for collision between circles that are rotated on the X axis (as if they were lying on a floor).
    Is there a way to do so with your class (you said it should work at any rotation, but I assume you meant any 2D rotation) or will I have to check in 2D before applying 3D transformation ?
    Thanks again.

  56. Tink says:

    I did mean any 2D rotation but can’t you just do the test on the 2D axis (x, y), and then just plot the points onto your 3D axis (x, z)?

  57. Horous says:

    I guess I’ll have to do it that way.
    Thanks for your reply, and again for sharing your work.

  58. Falcz says:

    Hey Tink, you have no idea how much this is appreciated. Thanks!

  59. Hey There !

    Really Great Class, thank you a lot Tink !

  60. [...] a function to create a Intersection Retangle in the hitting area. Very useful in game development. (http://www.tink.ws/blog/as-30-hittest/) MochiDigits “MochiDigits provides a quick, and easy way for developers to encode their sensitive numbers [...]

  61. [...] 為了解決這個問題 有人就開發了好用的class出來分享啦!! as2版跟as3版(我當然是用as3來測試囉!) 真的是讓這件事情變得無比的愉快 只要判斷: [...]

  62. Ian Reynolds says:

    I plan on using this code in an open-source AS3 platformer engine, but I’d like your permission first. Obviously you’ll get credit. Some pre-pre-pre-alpha samples are available on request.

  63. Tink says:

    Hi Ian

    Please feel free to use it.

  64. Ian Reynolds says:

    Thanks a lot! I plan on posting at least some of the engine soon.

  65. Anggie says:

    What a great class!

    I’m using it to detect valid/invalid drop positions in drag-n-drop within an as3isolib’s isometric scene.

    That accuracy parameter is very useful :-)

    Thanks for sharing, Tink!

  66. Troy Gilbert says:

    Looks like everyone has moved to the draw+draw.difference approach, I’m updating my version right now. Doesn’t look like anyone has found a faster generic pixel-perfect test.

    The accuracy parameter is an interesting tweak. Do you find it gains you much performance? My tests don’t show much difference between bitmap datas of different sizes (other than reduced memory), the most expensive step seems to be the setup and draws (at any usable size).

  67. [...] f his version is that it assumes the two objects have the same parent. Next, the venerable Tink posted his version that uses the same technique as The Actionscript Man but factors a more complicate [...]

  68. SiNT4X says:

    Hey Tink. Great class! So far I’ve figured it out.

    Only problems I’ve had were 1) your AS parser parses smilies – had to go in and fix two errors, but not a big deal.

    and 2) a little stranger error. Upon first using complexHitTestObject, I got a constant FALSE, perplexing me. Upon using complexIntersectionRectangle and tracing the values, the x and y values change when there is a collision, but the width/height remain 0, hence the constant false being returned.

    Any fix?

    Thanks :)

    `SiN

  69. Tink says:

    H SINT4X

    If you make a simple example, enable ‘view source’, then post the link here I’ll take a look.

    cheers

    Tink

  70. magicianseeker says:

    Tink, do you know how to solve this? I used two displayObject to detect either they collide or not and it returned sometimes true sometimes false. It doesn’t a problem when they are far apart–it returns true but it’s like that when they are near.

    btw, the displayObject are vector image.
    here is the code:

    public static function isHitting(hitter:DisplayObject,hittee:DisplayObject,parent:DisplayObject,precision:Number):Boolean
    { if(hittee.hitTestObject(hitter))
    {

    var rect1:Rectangle = hitter.getBounds(parent);
    var rect2:Rectangle = hittee.getBounds(parent);
    var rectInt:Rectangle = rect1.intersection(rect2);
    return searchCommon(hitter,hittee,rectInt,parent,precision)
    }
    else
    {
    return false;
    }
    }

    public static function searchCommon(object1:DisplayObject,object2:DisplayObject,rect:Rectangle,parent:DisplayObject,precision:Number):Boolean
    {
    var returnValue:Boolean = false;
    var p:Point = new Point();
    for (var j:int = rect.y; j <= rect.y +rect.height && returnValue == false; j+=precision) {
    if (returnValue == true) {
    break;
    }
    else {
    for (var i:int = rect.x; i <= rect.x + rect.width; i+=precision) {
    p.x = i;
    p.y = j;
    p = parent.localToGlobal(p);

    if(object1.hitTestPoint(p.x,p.y, true) == true && object2.hitTestPoint(p.x,p.y, true) == true)
    {
    returnValue = true;
    break;
    }
    }
    }
    }
    return returnValue;
    }

  71. Paul says:

    If I use this class in a SWF (say, to hit test 2 squares) and then load that SWF into another SWF at a y or x of anything but zero, it seems to break.

    Example:
    var loader:Loader = new Loader();
    loader.load(new URLRequest(“HitTest.swf”));
    loader.y = 200;
    addChild(loader);

    in order to fix this I had to change
    if( !target1.root || !target2.root || !target1.hitTestObject( target2 ) ) return new Rectangle();

    // Get the bounds of each DisplayObject.
    var bounds1:Rectangle = target1.getBounds( target1.root );
    var bounds2:Rectangle = target2.getBounds( target2.root );

    to

    if( !target1.stage || !target2.stage || !target1.hitTestObject( target2 ) ) return new Rectangle();

    // Get the bounds of each DisplayObject.
    var bounds1:Rectangle = target1.getBounds( target1.stage );
    var bounds2:Rectangle = target2.getBounds( target2.stage );

    which messes up the intersectionRectangle function iff I wanted to use that for anything beyond internal use for the HitTest class. Lucky for me, I don’t need that for anything else.

    I’m not going to try and fix this any further, but I thought you might be interested.

  72. Nick A says:

    I love the possibilities that are opened up with this.

    I used it with an inverted track clip and a sleigh for our companies viral campaign (http://www.d2digital.co.uk/viral.aspx) to test for the sleigh crashing into the side of the road.

    I posted the car/sleigh script on my blog; http://www.d2digital.co.uk/blog/actionscript_3_code_for_a_2d_driving_car.aspx

    Good work and thanks for enabling us to do much more cool stuff!

    Nick

  73. Ian Reynolds says:

    Hi-
    I posted a while back asking for permission to use this class in a game engine I was building and you might be interested in seeing how useful it was to me. Check out flyte-engine.org if you’re curious. Your class has been renamed Collision, I hope that’s all right. Thanks a lot!

  74. Stesha D says:

    Fantastic code! Good job.

  75. Piano Chords says:

    Thanks a bundle! Your hit test did the trick when my client said the hitTest wasn’t accurate. It’s insane that Flash doesn’t have a built in complex hit test? Or am I missing something? In AS2 wasn’t there a shapeFlag hit test? I don’t know why they don’t have something like that built in for AS3!

  76. Piano Chords says:

    How do you enable “view Source” for flash projects? I did a quick google search and didn’t see anything.

  77. It may be eluding me, but why in intersectionRectangle did you build your own intersection rectangle instead of just calling bounds1.intersection(bounds2)?

    Is there some performance boost, or just because you wanted to?

  78. Tink, you saved my sanity … Thanks for the hard work!!!

  79. InteractiveChaos says:

    Awesome work – I have had issues with loading a SWF into a MC, as the hittest is offset, and therefore doesnt work. By adding Pauls suggestion of

    if( !target1.stage || !target2.stage || !target1.hitTestObject( target2 ) ) return new Rectangle();

    // Get the bounds of each DisplayObject.
    var bounds1:Rectangle = target1.getBounds( target1.stage );
    var bounds2:Rectangle = target2.getBounds( target2.stage );

    It now works perfectly.

    Nice one people.

    Happy flashing

  80. el el says:

    Hi!

    Thanks a lot for the script, it’s just what I was looking for! F**** rocks!
    I am building my very first game with it – driving (parking) a car.
    One question/search for help: I am hit-testing my car against other cars. Now if my car moves at a certain speed it may overlap with an obstacle for so many pixels (in the very frame it recognized a collision) that it’s speed alone is not enough to get it off the hitTest. I created a work-around giving the car higher speeds momentarily, but still I’m looking for an elegant way of stopping the car RIGHT at the boundaries to the obstacle, rather than letting it overlap. I can’t think of a smooth and CPU-easy way of finding that exact spot where the car is supposed to stop. Can someone give me a hint on that?

  81. Nick A says:

    el el – are you using enterframe or intervals to call the hit testing?

  82. el el says:

    I’m using enterFrame at 24 fps…. So about every 41ms it enters one frame…

  83. Nick A says:

    cool, I was worried you were using intervals – nasty business they are with collision detection.

    okay, well I haven’t done what you’re describing before but I have some ideas (no actual code at the mo). I’m conidering doing a little dummy test of this and blogging it to follow my car code blog: http://www.d2digital.co.uk/blog/actionscript_3_code_for_a_2d_driving_car.aspx.

    I guess one way to do it would be with predicted position calculations. Is it only your car that is moving or the others too? If it’s just the car you control then why not get the x and y position of your car for the next frame (or next next frame etc) by using its speed and direction – do the collision detection for the predicted position – if it’s a collision then calculate the remaning distance to the object and only move it that much.

    Maybe you could have a copy of your car that is ‘alphad’ down to 0 which moves in relation to the predicted future position of the actual car and hit test that.

    I know these solutions aren’t 100% CPU friendly as they double the number of hit tests but can’t really think of much else.

    Good luck!

  84. el el says:

    Hi Nick,

    thanks for your replies, to begin with!

    You are suggesting what I’m already doing for some parts – I have a “ghost” serving as my forward ops – only if the ghost doesn’t get a hitTest I move the actual car. If not, the ghost remains at the car’s position, with speed set to 0… and so on. Now, logic dictates (I watch too much Voyager), that this is enough, but somehow it isn’t. I also experimented with calculating the remaining distance and moving only so far. Unfortunately I just didn’t have the time to do much about it, so I posted this question in the first place.

    I will conduct some more testing with our ideas on that, good to hear that you want to do the same with your driving sim! Thanks a lot. I will keep you posted.

    Best wishes!

  85. John Grateful says:

    I want to join the chorus in thanking you for your great work. I’m embarrassed to say I’ve been working several days to figure out a solution to detect when a rectangle (potentially rotated) leaves the area of another rectangle. The hitTestObject() gives false positives in some cases (as you know) and I couldn’t figure out a way around this. A thousand thanks.

  86. Tyler says:

    Thanks, so much, for this class. I had no problems using it, and wow.. thank you for that accuracy parameter. It makes a significant difference for difference uses of this class.

    Cheers!

  87. Ariranha says:

    Thx so much for this class, very usefull (I was using the as2 version from Grant Skinner).

    But on my fla stage how can I verifie the collision I put something like this:

    var detection:Hittest = new HitTest();
    detection = HitTest.complexIntersectionRectangle( obj1, obj2, 5);
    if(detection != null){
    trace(“detection is ok”);
    }

    Thx

  88. pkshetlie says:

    Merci c’ets genial :D

  89. Matt says:

    I just wanted to add to this ever-growing comments list my praise and thanks for this wonderful piece of code.

    Much respect for providing it free-of-charge as well. People like you help make the Internet be the place that it should be.

  90. Dechcaudron says:

    Thanks guy! I was looking for this to use it in my games!!! THAAAAAAAAAAANKS! I hope in the future I can make one and understand the whole code :D

    YOU ROCK!

  91. Mike says:

    Thank You! I really needed this.

  92. Andrew says:

    Here is a surprise, I too would like to tell Tink how awesome this is, I have used it in a previous project with no issues, just plug and play!

    Unfortunately, I am revisiting an old project where I am loading in many different SWFs in to my main application, and need to do a hit test on them. And, you’ve guessed it, I am running in to the same issue as Aaron and a few others above. I have made the change from .root to .stage, and this has made it better, however it does not appear that transparency is really being honored. I have created a barebones example of this and posted in a text document at http://www.andrewluly.com/test/hitTest.txt

    Anyone have any suggestions, that would be fantastic.

    Thanks
    -Andrew

  93. Andrew says:

    Hi, I have the same problem with the imported swf hit detection.

    matrix.tx = matrix.tx – (250); //set to the x-cords of the game
    matrix.ty = matrix.ty – (250); //set to the y-cords of the game

    Throws a syntax error, which is strange considering it works for other people.

    This is quite a large project with the main swf being capable of importing up to 5 swfs, most of them are already using Tink hit detection. One of those swf also imports another 5-6 swfs.

    So I can’t reprogram everything, I dont have the time.

    I’m scaling the imported swf down to a smaller size, but nothing I do works!

    Any kind of help would be much appreciated, as the entire project is due on 12 of January 2011.

  94. fdev says:

    Hi,

    I used this class few times before and for now I haven’t seen nothing better then your solution for this. However I have big problems now. I used your collision for checking hittest with mask for maze. It’s quite big, about 2500×2500 and it works like a charm in most cases. But I found that when you resize swf hittest stops working. Ok, I hardcoded 800×600 in html and there is no chance to resize it anymore. My game is almost finished and now QA found that it don’t work under Opera on MacOS :/ I’ve got no idea how it can be related to browser but it’s fact – game doesn’t work. I got same problem after changing environment to AIR.. On my computer everything works fine but on other machines, vista, and Mac (even on my mac mini) player goes crazy, moves chaotic over the screen. When I turn collisions off, it goes normal.. Please, if somebody can help me or even give me a clue where to search It would save my life..

  95. Lasercode says:

    Hey man,

    I wanted to view your examples, but they all lead to 404. Can you fix that please? Cause if I got no examples, I don’t know how to work with it :(

    Thanks in advance…
    Laser

  96. Ben Farrimond says:

    I’m relatively new with actionscript 3 and OOP but was looking for a method of accurate hit detection when I came across your class on your website. After scouring all of the comments trying to work out how to implement it into my project, I found your comment telling someone to go and research custom classes, which I did. But I still can’t figure out how to use it. At the moment I’ve renamed the class to ComplexHitTests and have saved the code as an actionscript file with the name ComplexHitTests. This file is in the Classes folder, and the Classes folder is on the same level as my FLA.

    How I perceive it to work, is that I need to import ComplexHitTests into my document class action script file (StealthGame.as), so I tried adding the line – import ComplexHitTests; – . However it still won’t let me use any of the functions such as complexHitTestObject. Any chance you could provide some insight? I feel like I’m doing something wrong that should be obvious to me, but isn’t.

  97. daniel says:

    First of all, thank You Stephen for saving me the t(h)inking and (probably a lot of) coding with this clever solution!

    Me too faced the bug on rotated displayobjects, but after a bit of digging around and debugging i found a possible solution to it.

    What is (was) giving -possibly- wrong results in Your class, is inside the getDrawMatrix method, namely the matrix.a and matrix.d part…
    The a and d properties hold information about scale AND rotation, but obviously, the stage-root-main (gladly) can’t be rotated, and like that it only holds useful values about the SCALE part of its transformation matrix.

    With that said, to get the correct (target.)matrix, before setting the translation parts (tx and ty)*, i apply the following scale to it:

    matrix.scale( 1/rootConcatenatedMatrix.a, 1/rootConcatenatedMatrix.d);

    I think the right order of combining the the matrix is Scale (+ Rotation) + Translation (leaving out the rotation part in this particular case).
    And just because some lines of code say more than lot-o-words..

    protected static function getDrawMatrix( target:DisplayObject, hitRectangle:Rectangle, accurracy:Number ):Matrix
    {
    var localToGlobal:Point;;
    var matrix:Matrix;

    var rootConcatenatedMatrix:Matrix = target.root.transform.concatenatedMatrix;

    localToGlobal = target.localToGlobal( new Point( ) );
    matrix = target.transform.concatenatedMatrix;
    matrix.scale( 1/rootConcatenatedMatrix.a, 1/rootConcatenatedMatrix.d);
    matrix.tx = localToGlobal.x – hitRectangle.x;
    matrix.ty = localToGlobal.y – hitRectangle.y;

    //matrix.a = matrix.a / rootConcatenatedMatrix.a;
    //matrix.d = matrix.d / rootConcatenatedMatrix.d;
    if( accurracy != 1 ) matrix.scale( accurracy, accurracy );

    return matrix;
    }

    Now it works like a charm…no more false results with rotated/scaled images!

    Thank You again for sharing this! Pure gold…

    cheers,
    daniel.

    * i was wondering (without having done benchmarks), would be the built-in method Matrix.translate( tx, ty ) faster than two individual assignments of tx and ty?

    • Tink says:

      daniel many thanks for you reply and suggestions and I apologize for it taking me so long to reply.

      I’ve edited HitTest.as to implement your fix and will commit it to the repo over the next day or so, and write a post about the changes.

      The problem with using Matrix.translate() is that it increments that values opposed to setting them directly, so I’ve left this part as it is.

  98. avatarbobo says:

    Hi! I discovered your code and this is exactly whay I need, but I don’t know how to make it work. Do I have to create a var, link it to ActionScript…? I would be really grateful if you tell me. Thanks!

  99. [...] And regarding the hit test – in this scenario none of the hit tests come with Flash (DisplayObject.hitTestObject(), DisplayObject.hitTestPoint(), and BitmapData.hitTest()) will do the job. You need more advanced hit test such as http://www.tink.ws/blog/as-30-hittest/ [...]

  100. [...] And regarding the hit test – in this scenario none of the hit tests come with Flash (DisplayObject.hitTestObject(), DisplayObject.hitTestPoint(), and BitmapData.hitTest()) will do the job. You need more advanced hit test such as http://www.tink.ws/blog/as-30-hittest/ [...]

  101. Mathijs Segers says:

    Man I love this, I’ve been searching for hours for a pixel detection which would not lag my ass off when I’m checking on huge ass images.

    I’m an idiot for even wanting this but now it actually works smoothly cause I can change the accuracy.

    Thanks a bunch!

  102. Fayçal says:

    Hi tink

    thank you for your function but the links to exemples doesnt work can you please give us a new link

  103. [...] target1:DisplayObject, target2:DisplayObject, accuracy:Number );參考資料:Tink » Blog Archive » AS 3.0 HitTest 本篇發表於 Action Script, Adobe Flash, 筆記 並標籤為 Action Script 3.0, Adobe Flash, [...]

  104. 微微 says:

    hello,i have several questions,may be stupid:
    1,why use “root”,not “stage”?do they have differnce?
    2,when i test a_mc and b_mc(you know they are common rect MovieClip),your class behaves perfectly,however,when rotate a_mc,it gives a result not accurate。
    can i get your email,may i email you my test-swf and code in detail?
    hope you will see this soon

  105. 微微 says:

    i want to point out some errors that exit at method getDrawMatrix(),just my own opinion:

    protected static function getDrawMatrix( target:DisplayObject, hitRectangle:Rectangle, accurracy:Number ):Matrix
    {
         var localToGlobal:Point;;
         var matrix:Matrix;
     
         var rootConcatenatedMatrix:Matrix = target.root.transform.concatenatedMatrix;
         //although the following statement has an error,i love it for i's short and clever,i usually write it like this
         //localToGlobal = target.parent.localToGlobal( new Point( target.x,target.y) );,very stupid,haha
         localToGlobal = target.localToGlobal( new Point( ) );
         matrix = target.transform.concatenatedMatrix;
         //all through the class,you set root as fundamental coordinate system,but obviously,localToGlobal use stage
         //as Reference Coordinate System ,when root has no offset to stage,the error was hidden,however,you just add
         //a statement to document class like "this.x+=50",and test patiently,you will find HitTest Class will give an imprecise return-value
         matrix.tx = localToGlobal.x - hitRectangle.x;
         matrix.ty = localToGlobal.y - hitRectangle.y;
         //the purpose of the following two statements:convert target.tansform.concatenatedMatrix to root-coordinate system
         //am i right?but you should use scale().Directly handling matrix.a or matrix.d is not the same function as scale() 
         //when matrix.b or matrix.c is not 0(when targets rotate).i mean,only when matrix.c and matrix.b is 0,you can use
         //the following two statements to scale matrix,once they were not 0,the following two statements will lead error.
         //at most cases,the errors where hidden because rootConcatenatedMatrix.a and rootConcatenatedMatrix.d are 1,so the 
         //following two statements do nothing ,then matrix has no change.just add a statement to document like "this.scaleX
         //=2",and test rotated object,you will find HitTest Class will give an imprecise return-value
         matrix.d = matrix.d / rootConcatenatedMatrix.d;
         if ( accurracy != 1 ) matrix.scale( accurracy, accurracy );
         //i don't know why you use "root" as fundamental coordinate system,if you use "stage",the HitTest class will not need
         //to handle so many coordinate convertion,isn't it?well,i guess there must be some advantages when using "root".
          return matrix;
    }

    still use “root” as fundamental coordinate system,i give a version of getDrawMatrix().

    protected static function getDrawMatrix( target:DisplayObject, hitRectangle:Rectangle, accurracy:Number ):Matrix
    {
         var rootConcatenatedMatrix:Matrix = target.root.transform.matrix.clone();
         var matrix:Matrix = target.transform.concatenatedMatrix.clone();
         rootConcatenatedMatrix.invert();
     
         matrix.concat(rootConcatenatedMatrix);
         matrix.tx = matrix.tx- hitRectangle.x;
         matrix.ty = matrix.ty - hitRectangle.y;
         if( accurracy != 1 ) matrix.scale( accurracy, accurracy );
         return matrix;
    }

    i have test this method, it will give accurate return – value when ”root“ rotate, offset, or scale, you can check it btw, when i did the collision test, i find that return – value weil be imprecise when i scale the flash player window with mouse , i guess the reason is taht window – scale may change target’s concatenatedMatrix.

    best wishes.

  106. [...] way to check collision with wall and have the object stop. Click the red dot to start. Use’s Tink HitTest class. Here’s the [...]

  107. Ookami says:

    No source, no point.
    Didn´t have a backup for your upload files? man…

  108. [...] Consultez la méthode de détection des collisions plus précise sur le site Tink. [...]

Leave a Reply