A while back I posted a demo of shape-based hit detection in Flash 8. At the time, I wasn't allowed to post the source code, but promised I would later. So here it is.
The com.gskinner.sprites.CollisionDetection class is really simple to work with, there is a single static method called checkForCollision with four parameters:
checkForCollision(movieClip1,movieClip2,alphaTolerance);movieClip1, movieClip2 - The MovieClip instances to check for collision.
alphaTolerance - a number from 0 to 255 that specifies the transparency tolerance when testing the collision. A higher number will increase the tolerance (ie. allow more transparent parts of the MovieClip to register collisions). Defaults to 255.
Returns a Rectangle object specifying the intersection of the two MovieClips in the _root coordinate space, or null if they do not intersect.
Check out the original post for more information on how the class works.
Click here to download. It includes two simple demos to help you get started with it.
Comments (59)
Hi grant - looks good.
A couple of questions:
I gather this is derived from the classic bitmask/ XOR method - is that right? Also, how well does it scale? Have you tried it with larger numbers of objects?
Posted by: Alias at October 4, 2005 06:30 PMURL: http://www.proalias.com
Alias,
Similar idea to XORing, but taking advantage of the player functions - it's basically drawing clips onto a bitmap in a specific color using a difference blen and looking for a specific color in the result.
It runs better than I would have expected, partly because I'm using boundary intersections to minimize the bitmap dimensions, and rule out clips quickly.
I have a version that's fully integrated with my proximity management logic that runs really well, because it only uses a single BitmapData object. I might release that one in the future.
Posted by: Grant Skinner at October 4, 2005 06:57 PMURL: http://www.gskinner.com/
Hi Grant,
Cool - I'm working on a similar proximity manager which uses spatial hashing tables. I've been taking a more geometric approach to narrow phase collision detections so far, but I think this approach is definitely worth considering as well.
Any thoughts on collision resolution with this approach? Have you thought about maybe using the graphical intersection data to determine a penetration vector?
Posted by: Alias at October 5, 2005 04:27 AMURL: http://www.proalias.com
Yes, I've been thinking about doing that. Given the velocities and the intersection boundaries it should be fairly simple to get a rough vector.
Posted by: Grant Skinner at October 5, 2005 01:16 PMURL: http://www.gskinner.com/
lol why does everything have to have an ugly drop shadow or blurs in everyones experiments now.... it's like when lens flare was introduced in photoshop
Posted by: mario at October 5, 2005 03:53 PMURL:
Offtopic: As i don`t see answers on other pages, i`m writing to the latest post. How much is gProject? 35$ or 41.50 ? kagi.com tries to include VAT and asks for shipping addres, but i dont need anything to be shipped, just the download for 35$! why do they want to charge me additional 6 bucks? ok, its not that much, but still kinda silly..
Posted by: Valters Boze at October 6, 2005 01:50 AMURL: http://www.djnet.lv
Hey, I'm using this code in a game I'm making.
I've got this code in the car Movie Clip:
import com.gskinner.sprites.CollisionDetection;
onEnterFrame = function () {
for (n=1; n carNo = "car"+n;
thisName = _name;
if (CollisionDetection.checkForCollision(_root.cars[thisName], _root.cars[carNo], 120, _root.cars)) {
if (carNo>thisName) {
if (thisName == _root.activeCarNo) {
_root.speed *= -1;
_root.cars[carNo].speed *= -1;
} else {
_root.cars[carNo].speed *= -1;
_root.cars[thisName].speed *= -1;
}
}
}
}
};
it doesn't work for some reason???
I also used the same code in your example (with the spinning thing) to make each ball hit each other, which worked???
What's wrong?
Posted by: Nick at November 20, 2005 10:10 AMURL:
the 'for' statement should be:
for (n=1; n carNo = "car"+n;
Posted by: Nick at November 20, 2005 10:12 AMURL:
? it doesn't work
Posted by: Nick at November 20, 2005 10:13 AMURL:
when i try to refer to the mc within another movie clip the hit detection doesn't seem to work
if (CollisionDetection.checkForCollision(this,target,120,_root.player)) {
play();
_root.player.health -= 2
delete(onEnterFrame);
}
and i set the target to body(a mc in the mc of player) no hits end up being detected.
any ideas?
Posted by: paul at November 22, 2005 03:26 PMURL:
sorry for my english!
Posted by: Diego Rotondo at March 4, 2006 01:24 PMit's very advanced for me, y just need a variable that tells me the _x and _y position of the collision. i'm buileding a city map, that when the people put the two streets they find, the map moves to de collision of two,
i hope u understand
thanks a lot
Diego
URL: http://www.pixelismo.com
This is awesome, but I can't seem to open the .fla file with Flash MX 2004 (PC). Do you have a version that works for that?
Erik
Posted by: Erik J at March 23, 2006 09:25 PMURL:
Hey paul
i'm kind of a newb and only 12 but i know how to
fix yur problem:
"checkForCollision(this,target,120,_root.player)"
The "target" should b a target path to the movieClip its checking for collision with
ur welcom
Posted by: zai at July 24, 2006 10:32 PMURL:
Hi,
this looks very interesting.
One question though: I tried the example but nested the rotating shape inside another mc. When this parent mc is not positioned on (0,0) the hitdetection does not work properly anymore.
Any thoughts on how to sove this problem?
Thanks,
Arjen
Posted by: Arjen at August 4, 2006 03:29 PMURL:
I am a very big newb. and am hoping that you guys can help me out because you seem to know what your talking about...
Once i have the source script from a site... how do i put it to use.....
i have flash mx proffesional 2004 v7.2
please help....
Posted by: abdi at November 11, 2006 08:34 PMURL:
Is there any problems with masks ?
This code works perfectly on my clips, but if un use a setMask on it, this collision checker returns nothing... :-/
Excellent work anyway !
Posted by: Abalam at November 19, 2006 01:19 PMURL:
Excellent work gskinner.I must congrat you for this work.In the past I tried checking collisions using bitmaps but it was too hard as It didn't "hit" me to build a lcass for this (probably because my oop knowledge then was limted)
As I played with CollisionDetection class I saw a small(that could become big when you are developing something that has big movieclips) flaw.Working with bitmaps as we all know is very tricky and if you don't want that your little swf game take up the entire Comp Memory you should be sure that the memory is freed up as the bitmap is not needed anymore.
In my opinion you should add right before it helped me a lot with a big bitmap
Posted by: Iancu Oliver-Bogdan at November 28, 2006 07:38 AMMy Regards,
Oliver
URL: http://www.biodegradable-software.com
Great!
Posted by: m.sibbald at December 1, 2006 04:02 AMI'm trying use this in my flex project. It works great, but...there are times that my plyer crashes. And i fihures out that it's the blendmode that is given me problems.... Any ideas??
URL: http://labs.flexcoders.nl
I have to install de class file? o just writing this setence "import com.gskinner.sprites.CollisionDetection"
the script works?
Posted by: cam at December 5, 2006 06:00 PMURL: http://no
hi what if I want a collision detection with an object with the alpha property set to zero?
Posted by: Oscar Merlos at January 13, 2007 07:09 PMURL: http://none
hi guys
what I meant in the above post is what if you want to check the collision of an object inside an object for example:
CollisionDetection.checkForCollision(_root.tubo,this.sombra);
this aint working and I guess is because we're not really passing a MovieClip (checkForCollision(p_clip1:MovieClip,p_clip2:MovieClip...) to the function but an adress of the movieclip
tnx in advance
Posted by: Oscar Merlos at January 13, 2007 07:34 PMURL: http://none
Hi Grant!
This class was very useful but there is still a bug.
in the static checkForColllision function you have:
var bounds:Object = {};
bounds.xMin = Math.max(bounds1.xMin,bounds2.xMin);
bounds.xMax = Math.min(bounds1.xMax,bounds2.xMax);
bounds.yMin = Math.max(bounds1.yMin,bounds2.yMin);
bounds.yMax = Math.min(bounds1.yMax,bounds2.yMax);
but you have switched the Math.max and Math.min methods. change the Math.max to Math.min and vice versa and it works like a charm =) !
Sincerely,
Posted by: Reinier Rossen at February 7, 2007 08:23 AMReinier Rossen @ www.mediamonksgames.com
URL: http://www.rrossen.com
I am having the same problem as several others:
The function does not seem to work when using MovieClips outside of the root. For instance:
checkForCollision(mario_mc.foot_mc, goomba_mc) would not work because I'm checking for "foot_mc", which is inside of a movie clip.
Is there any workaround to this?
Posted by: Eric at March 15, 2007 04:48 PMURL: http://www.motionsmith.net
I've just tested with clips in different parents, and it seemed to work fine. I'm not certain if that's because the version I have locally is more up to date than the one that was online, or if it's simply because I'm not reproducing the issue properly.
I've updated the zip file with the latest version of the class, and added a third demo FLA that shows it working.
If you can reproduce the issue with this file, please let me know - I'd like to see examples of the problem.
Posted by: Grant Skinner at March 15, 2007 10:03 PMURL: http://gskinner.com/blog/
Ok. I tracked down an issue with nested clips thanks to an example provided by Eric. I've updated the zip file with the latest class file. It should now work properly with nested clips, and any transformations (scaling, rotating, etc) of the targets or their parents.
I also removed the fourth parameter (scope), as it will not work correctly with this updated version. The intersection rectangle will always be returned in the _root's coordinate space.
Posted by: Grant Skinner at March 16, 2007 09:48 PMURL: http://gskinner.com/blog/
Great class. However, I'm having some trouble utilizing this within my game. I have the collision detection placed on my character's MC and I'm using it within the motion coding. Basically, it checks if the key is down and the character isn't touching a wall, allow the character to move.
The problem with this is that if the character IS touching a wall, it won't allow movement to get away from it, so the character is stuck.
Previously I could work around this when using hittesting by placing a "+speed" variable after the x/y coordinate detection, but with this class, I'm not sure if you can do that. Could anybody help?
This is the code on the character (part of it, at least)
onClipEvent (enterFrame) {
speed = 7;
if (playable==true) {
if (Key.isDown(Key.LEFT) && !(CollisionDetection.checkForCollision(this, _root.boundary, 10))) {
this._x -= speed;
this._xscale = -100
}
if (Key.isDown(Key.RIGHT) && !(CollisionDetection.checkForCollision(this, _root.boundary, 10))) {
this._x += speed;
this._xscale = 100
Posted by: Kyle Kozinski at March 18, 2007 04:24 PMother than that, the code works great. The hit detection is much more accurate that old methods.
URL: http://www.jkmd.net
I really need some help with a game a friend and I are making. I need a script that can detect a wall that is very obscure, kind of like your shape above but the player can't get behind the wall. I have a wall script I'm using now but it requires that I put tiny shapes around the object. I am trying to overcome the bounding box that is created from contering the object to a symbol. I want to use the arrow keys and for some reason I can't use yout script found here. I'm kind of bad with action script but I know some basics. If someone could post a solution or send me an Email at LJW10000@myactv.net I would be greatly appreciative.
Posted by: Lawrence at March 19, 2007 11:59 AMURL:
I have testet the new sourcecode which should work with nested movieclips, but I cant make it work? Ive just opened the "CDDemo1.fla" file and made a new movieclip inside both the mc1 and mc2 movieclip and called them hit1 and hit2. As I understand it should it work if I write as this:
var collisionRect:Rectangle = CollisionDetection.checkForCollision(mc1.hit1,mc2.hit2,120);
This dont work. Can anyone tell me why?
Thanks
Posted by: Rasmus at March 28, 2007 06:29 AMURL:
I see how the example can display a rectangle of the collision area, but how did you get it precisely in your first example? The circle in the upper-left corner shows the EXACT area of collision as opposed to a rectangle covering all area.
Can you release that code?
Thanks!
Posted by: Dan at April 25, 2007 01:24 AMDan
URL:
Hello Grant,
This collision detection class is great, but there is one problem. During run time, when you make the size of the window, which holds the swf, bigger, the collision detection doesn't work anymore.
This problem also occurs on the 2 demo's that are included in the zip.
Is there any solution to that problem?
I have also created a game using you collision detection class. If I resize the window my game is running in the collision detection doesn't work anymore.
Kar Ching
Posted by: karching at May 7, 2007 01:29 PMURL:
Hi Grant,
You saved my day! I was all day frackin around with hittest and not getting it working cause I need to have a collision detection with a line drawn by the drawing api and flash puts a hitbox around it (grrrr)... So, there I was, headache and all, till I found this website.. Thanks!
greetings,
Jesse//
Posted by: Jesse at May 21, 2007 11:54 AMURL:
Grant,
Any possibility of converting this to AS3? If so, I would love it as soon as possible! Thanks,
Eric
Posted by: Eric Smith at May 22, 2007 01:08 PMURL: http://www.motionsmith.net
Nevermind, I converted it.
Posted by: Eric Smith at May 22, 2007 01:17 PMURL: http://www.motionsmith.net
Hi Grant and readers,
We have an actionscript 3 version of the skinner collision detection class. You can download it on our blog:
http://labs.boulevart.be/index.php/2007/06/08/skinner-collision-detection-in-as3/
It's not yet been tested to it's limits so improvements are always welcome.
Thanks Grant for the amazing stuff you do and for the source code you share with us.
Posted by: Wim Vanhenden at June 8, 2007 02:51 AMIt's been a big help for us.
URL: http://labs.boulevart.be
hi, this looks really cool but i'm a newbie to flash. basically i have 4 floating movie clips that can be clicked on, they then motion tween themselves to the center of the stage and back again. at the centre of the stage i have a persons head. and i want it to flash red when the floating movie clips fly into it. i know no action scripting but any way you could help me out here?
Posted by: Regan at June 10, 2007 05:44 PMURL:
Hi, is there a simpler version of this script which is flash 7 or even 6 compatible? the current script returns a area of intersection which i dont need, a simple return true/false would be great. Any help is much appreciated : )
Posted by: Si at June 20, 2007 09:54 AMURL: http://www.graphic-euphoria.co.uk
Any chance we could get a peek at the version that uses a single BitmapData? I'm assuming you allocate some maximum size BitmapData then do all of your operations to different sections of it? What kind of performance difference do you realize?
Also, any tips on what the biggest offenders are in the algorithm? Should I look to minimize the amount of overlap in the objects (make the BitmapData's smaller), or is just the allocation and drawing of the BitmapData's that dominates the equation?
In my case, all of my objects are BitmapData objects, but they may be rotated or scaled... is this still going to be the best option for pixel perfect detection (I don't have any shapes or vectors)?
Thanks,
Troy.
Posted by: Troy Gilbert at June 21, 2007 11:51 AMURL: http://troygilbert.com/
Hey Kar Ching,
I stumbled on your resizing problem a few months ago when I had to build a projector version of a game using Flash.
I did some research on the internet about flash bug and resize and found nothing on how to get it working with normal resize.
By tracing Gran's code I observed that it's happening because after resize flash draws the bitmapData in an eroneus location.
I will do more research...until then if you want to bypass the issue just add
Stage.align="TL";
in your fla.This will fix the collision detection
Posted by: Oliver-Bogdan at August 2, 2007 07:59 AMUntil next time...
Regards,
Oliver
URL: http://www.biodegradable-software.com
this was exactly what I need! I love u man. haha =D
Posted by: dz at August 28, 2007 11:46 AMURL: http://ignorewhite.com/blog
I want to thank first for this great example of collision detection and say some words about it. I found some mistakes and here there are:
1. The first boundary check it could be done by using the default hitTest() method = clip1.hitTest(clip2) but that's optional
2. You must change the xMin/xMax and yMin/yMax assignments. It calculates different coordinates and don't return the real image boundary.
3. The thing I said in 2. is actually not necessary because you these xMin/xMax and yMin/yMax methods to give the "img" object _width and _height parameters. We've got our big error here. Done in this way works perfectly but if the Stage is not zoomed! I mean if it is in its original size, when you make it fullscreen for example it doesn't work. I'll explain why after a few lines.
Here's my way: you give the "img" object these _width and _height parameters:
1. You create a movie clip in your flash project with these parameters: _x=0; _y=0; _width=Stage._width; _height=Stage._height (the last two parameters is the original size of your flash project). This movie clip appears as a stage mask or something like that, that's why I'm giving it this name "stage_mask"
2. Make the "stage_mask" with 0% _alpha, so it can't be visible;
3. Use the path to your "stage_mask" Movie clip in your CollisionDetection.as (e.a. _root.gameclip.stage_mask)
4. Add this to the "img" initiate in the CollisionDetection.as file:
_root.gameclip.stage_mask._width, _root.gameclip.stage_mask._height
instead of the bounds2.xMax-.... I don't remember it :)
What actually make it don't work in the previous version:
when in 200% zoom for example the .getBounds method returns the xMin/xMax and yMin/yMax coordinates of the movie clip on the stage (calculated with these 200% of zoom) which means if your MC's width is 100 pixels it returns 200 because of the 200% zoom, but when you make flash draw a 200 pixels rectangle on the stage and you're in 200% it actually appears as 400 pixels because of the zoom! What it actually happens is that the image you want to draw has less size than its movie clips. And so the img.getColorBoundsRect(...) method can't find anything.
If someone has some questions about this or want the reworked CollisionDetection can write me an e-mail: ivo_yankulovski@abv.bg
Posted by: Pacific at October 23, 2007 02:38 AMURL:
I tried using this to make a game where you avoid astriods in a space ship and i attched this script to the layer, and its not working. Can someone tell me why
if (CollisionDetection.checkForCollision(_root.spaceship_mc,_root.astriods_mc,255)) {
gotoAndPlay("you lose", 1);
} else {
this.gotoAndStop(1);
};
//end of code
it keeps making the game restart everytime I try to go to that scene...Please help.
Posted by: Chrisf at November 13, 2007 07:03 PMThanks
URL:
I would also like to be able to make my project fullscreen without the collision detection stopping working! I understand Stage.align="TL"; will fix it. But my project does not suit being aligned to anything but the center.
Any help would be fantastic.
Posted by: Jon at February 27, 2008 10:16 AMThanks,
Jon
URL:
There is a version in as3?
Posted by: Taytus at March 4, 2008 09:57 AMURL: http://mp3division.com
I made a test program to check collisions of lots of objects on my blog, and have made a tweaked version of this with a few bits borrowed from troy gilberts version and i gained a decent speed up in some cases. I hope it's ok to distribute my modified version, i've given you full credits and link in my blog. I'm going to try merging this with your proximity grid system and see if that improves the speed by a decent amount. Let me know if it's ok to share my modified version on my blog, it's my first actionscript 3 demo - only been programming in AS3 for a short while :)
Posted by: ActionscriptMan at March 18, 2008 03:42 AMURL: http://www.adventuresinactionscript.com/blog/15-03-2008/actionscript-3-hittestobject-and-pixel-perfect-collision-detection
Sorry, bit of a noob at the whole programming lark - let me see if I've got this right. THe last parameter (alpha tolerance), will mean that the bigger the number, the more faded out the MC can be for the Collision Detection to detect something. Is that right - or the inverse of that?
Posted by: Haddock at April 6, 2008 01:19 PMURL:
Hi -
I just wanted to extend my thanks for your foundational work on collision detection. I just included Troy Gilbert's most recent version of your class in an open-source piece. A link to the project can be found below:
https://netfiles.umn.edu/users/frah0005/www/dynamicSpace/dynamicSpace.html
Posted by: Robert at April 8, 2008 02:30 PMURL: http://www.umn.edu/~frah0005
Hi all , I'm using checkForCollision for two MovieClips, One mc from my library and the other from dinamyc lineTo movie clip.
I'got this error:
1046: Type was not found or was not a compile-time constant
Posted by: charli_e at April 21, 2008 05:47 PMURL:
Hi, Grant. This is a great work.
Posted by: Ozgur Uksal at May 5, 2008 08:38 AMURL:
Hi,
I used this class and it was really great, but i found an error when stage resize.
Because the coordinates change and when the script tries to getBound() the values are wrong.
So i update my class to include this code:
// get bounds:
var bounds1:Object = p_clip1.getBounds(_root);
var bounds2:Object = p_clip2.getBounds(_root);
var nDifW:Number = Math.round((Stage.width - 800)/2);
var nDifH:Number = Math.round((Stage.height - 600)/2);
bounds1.xMin = bounds1.xMin + nDifW;
bounds1.xMax = bounds1.xMax + nDifW;
bounds1.yMin = bounds1.yMin + nDifH;
bounds1.yMax = bounds1.yMax + nDifH;
bounds2.xMin = bounds2.xMin + nDifW;
bounds2.xMax = bounds2.xMax + nDifW;
bounds2.yMin = bounds2.yMin + nDifH;
bounds2.yMax = bounds2.yMax + nDifH;
I hope that can help someone, since i lost one day until i discover what is going wrong :)
Posted by: Filipe Murteira at June 4, 2008 10:28 AMURL: http://www.filipe-murteira.com
Hi,
Posted by: lauren at June 5, 2008 12:04 AMNice class, thankyou. I can get it working fine in player 9 but when i test publish for player 8 it gets buggy - seems to be translating incorrectly. I see that you recommend 8r50 but all the adobe documentation for the various methods used says they're good for player 8.
Can you point out the 8r50 code or suggest a player 8 workaround please?
(I noticed this because my hit object is heart-shaped instead of square or round).
Thanks
URL:
Further to my player comment. I realised it was actually a drop-shadow filter on the parent clip that was causing the problems. I've re-jigged my clips so as to avoid this and it works fine in player 8 now - albeit with the Filipe Murteira stage-resize friendly code. Brilliant - thanks guys!
Posted by: Lauren at June 5, 2008 04:58 PMURL:
Hi Filipe Murteira ,
Posted by: Aries at June 17, 2008 04:30 AMI have the same problem, thank you very much for share fix class. It's very usefull
Nike regards
Aries (Vietnamese)
URL:
Great class btw. I'm finding that by using setMask the collision doesn't work. Has anyone found a solution to this? I've tried exploring around with getBounds to no avail.
Thanks!
Posted by: brian at July 29, 2008 08:37 AMbrian
URL:
I was banging my head against a wall trying to get the latest version of this routine to work correctly when our module was within a container scaling it to fullscreen (not the built-in Flash function, but using swhx to achieve the job). Here's what we found...
When you use mc.transform.concatenatedMatrix it rattles all the way back to the absolute _root. However, if any movieclips are set with _lockRoot=true on the way, when you getBounds(_root) you're working with the co-ordinate space of the _lockRooted movieclip, which could (and, in my case, was) scaled differently. Taking the concatenatedMatrix as my cue, I reworked the routine like this:
// draw in the first image:
var mat:Matrix = p_clip1.transform.matrix;
var clipParent:MovieClip = p_clip1._parent;
while (clipParent != _root)
{
mat.concat(clipParent.transform.matrix);
clipParent = clipParent._parent;
}
This manual concatenation has fixed all my fullscreen issues. I've also made two other changes, one vital to prevent memory leaks, and one just to beautify it a little (IMHO)...
At present, the bitmap used for the collision detection is never disposed of. This is A Bad Thing. I've added img.dispose() immediately after the getColorBounds() command.
And we have in our company code library a function to return the bounds of a clip as a flash.geom.Rectangle object. Very simple function, it just remaps the xMin, yMin etc. to the correct properties for a Rectangle. By doing this at the top of the code, where the bounds of the clips are calculated, you can tidy up the code a hell of a lot:
// rule out anything that we know can't collide:
if (!bounds1.intersects(bounds2))
{
return null;
}
// determine test area boundaries:
var bounds:Rectangle = bounds1.intersection(bounds2);
Much nicer.
Posted by: Steve Anderson at July 31, 2008 03:07 AMURL: http://www.awenmedia.com
what a bad tut.. atleast put an example. I can't figuire it out
Posted by: zzzz at August 15, 2008 09:12 PMURL:
zzzz - not to belabour the obvious, but this is not a "tut", and it does include an example file. There's not much to "figure out" other than copying and pasting the code.
Posted by: Grant Skinner at August 15, 2008 09:54 PMURL: http://gskinner.com/blog/
o my bad i just saw it now
Posted by: zzzz at August 17, 2008 02:09 PMURL:
Hi Grant
Posted by: andrew donald at August 28, 2008 02:16 PMI had a fun day today working with your Collision Detection script. Its very slick. I have adapted it for a maze based game but I was hoping to try and add a way of restricting the moving object to the edge of the maze walls instead of walking through them. I would paste my effort here but its a little embarassing :)
I wonder... how would you do it?
andy
URL:
I didnt get it working with the fixes from the comment. Can someone from above please link his class where the fullscren/resize-Bug is fixed?
Posted by: Sebastian Salzgeber at September 23, 2008 11:35 AMURL: