A Flash Developer Resource Site

Page 1 of 2 12 LastLast
Results 1 to 20 of 21

Thread: Hitest And Basic Collision

  1. #1
    M.D. mr_malee's Avatar
    Join Date
    Dec 2002
    Location
    Shelter
    Posts
    4,139

    Hitest And Basic Collision

    hopefully this will stop all the hitTest questions. If you have something helpful to post please do.

    THINGS YOU SHOULD KNOW ABOUT HITEST

    - hitest can find a collision between two movieclips or a point against a movieclip
    - hit testing uses global coordinates
    - the two methods of hit testing are: movieclip : movieclip or movieclip : point
    - movieclip to point can accept a thrid parameter, called a shape flag, if this parameter is set to true, it will test the actual shape of a movieclip (this can be anything) if it's set to false it will check the bounding box of a movieclip, this is a bounding box is always a square or rectangle
    - hit testing will return a boolean value, meaning: true or false, which also means you can store a hitTest in a variable
    - hit testing does not position objects, it use is for checking a hit
    - hit testing should be avoided with complex mathematical collisions such as Rigid body's
    - hit testing is a good simple way to check a hit without slowing your game down

    if you remember the above rules, then hitTesting will be a breeze

    SIMPLE HITEST

    MOVIECLIP : MOVIECLIP HIT TESTING
    to perform a simple hit test between two movieclips:
    Code:
    if (player.hitTest(enemy)) {
    	trace("hit");
    }
    MOVIECLIP : POINT HIT TESTING
    to perform a hit test on an objects actual shape and a point:
    Code:
    if (player.hitTest(enemy._x, enemy._y, true)) {
    	trace("hit");
    }
    the first two parameters are numbers, they don't have to be the enemy's position, they could be any number you want, the third parameter is the shapeflag, when set to true it checks the numbers against the players shape

    to perform a hit test on an objects bounding box and a point:
    Code:
    if (player.hitTest(enemy._x, enemy._y, false)) {
    	trace("hit");
    }
    COLLISION RESPONSE
    before any additional checking, nothing is known about the hitTest, we only know that it is true or false, so we need to use other methods to respond to the collision

    IF STATEMENT
    the "if statement" can be very limited, since we know nothing about the intersection of the hitTest, we can only guess, a common solution is:
    Code:
    var speed = 10
    if (!landscape.hitTest(player._x, player._y+speed, true)) {
    	player._y += speed;
    }
    WHILE LOOP
    this works by running a loop while an object has detected a collision, a loop is needed so that the object moves in the correct direction the exact amount of pixels required. A while loop is used here because we are not sure how far the movieclip has intersected another movieclip, so we do some operations "while" the condition is true
    Code:
    while (landscape.hitTest(player._x, player._y, true)) {
    	player._y--;
    }
    the above code checks the x and y coordinates of the player and moves it up 1 pixel every time a hitest is found. The drawback to this solution is that it can be slow with the more directions you are checking for.

    ADVANCED COLLISION DETECTION

    HIGH SPEEDS
    sometimes an object will be moving very fast and needs to check collision between an object which is thinner than the movieclips current speed, odds are that the movieclip will miss the detection of a hit because its moving too fast. An easy way to overcome this is use a loop to check the positions between the current movieclips position and its next position, so that anything in between will be detected. This method uses the shapeflag hitest again.
    Code:
    //players inital velocity's
    player.vx = 300;
    player.vy = 300;
    //code run on every frame
    onEnterFrame = function () {
    	//grab the players actual speed
    	var speed = Math.sqrt(player.vx*player.vx+player.vy*player.vy);
    	var vx = player.vx/speed;
    	var vy = player.vy/speed;
    	//loop through the coordinates from the player's current position to its next position
    	for (var i = 0; i<speed; i++) {
    		var x = player._x+(i*vx);
    		var y = player._y+(i*vy);
    		//perform a shape based collision on the landscape based on the current coordinate
    		if (landscape.hitTest(x, y, true)) {
    			//position the player at the correct coordinate
    			player._x = x;
    			player._y = y;
    			//stop the movement of the player
    			player.vx = 0;
    			player.vy = 0;
    			//no need to continue checking additional points, so we break from the loop
    			break;
    		}
    	}
    	//update the players position
    	player._x += player.vx;
    	player._y += player.vy;
    };
    this code assumes the player and landscape are in one movieclip, and this code is put on frame 1 of that movieclip. You can easily change it to your needs by changing the names.

    OPTIMISED HIGH SPEEDS
    the majority of the above code is used here as well. Except we need to change how many pixels are checked in the loop, if we make this number smaller the collision checking will be faster and less strain on the CPU. But the accuracy of the checking will be smaller. By simply adding and changing the next lines we can optimise the checking:
    Code:
    //to lessen the strain of the loop, we want to only check a few points
    //the higher the step, the less checking we have to do, but the less accurate the check will be.
    //if our speed is 70 and the step divisor is 10, that means every that every 7 pixels between the start and end point will be checked
    //always keep the step smaller than any part of the movieclip to be hitTested, this will stop anything from missing a collision
    var step = speed/10;
    var vx = player.vx/step;
    var vy = player.vy/step;
    //loop through the coordinates from the player's current position to its next position
    for (var i = 0; i<step; i++) {
    MULTIPLE OBJECTS
    using loops again we can check collision between multiple objects.

    If you wish to check collision between all movieclips within another movieclip (common scenario: “enemies” within an “enemy’s” movieclip) you use a “for in” loop to check. The same code can be used to check an array or an object. I recommend the object method: var myObjects = {} as the checking is much faster. Using the typeof command eliminates checking of anything in the enemyParent movieclip that is not a movieclip, like objects or variables. Using the "typeof" command is optional.
    Code:
    function checkHit(player, ob) {
    	return player.hitTest(ob);
    }
    for (var i in enemyParent) {
    	var enemy = enemyParent[i];
    	if (typeof enemy == "movieclip") {
    		if (checkHit(player, enemy)) {
    			trace("hit");
    			//this is where you can run your collision response function
    		}
    	}
    }
    By creating an additional function we can pass two movie clips, (which don’t have to be player and enemy) and perform a hitest between them, you could also run a collision response script from the returned Boolean

    BASIC MATHEMATICAL COLLISION

    CIRCLE : CIRCLE COLLISION
    Circle to circle collision is actauly quite easy, all we need to do is get the distance between two objects and compare that distance to the sum of both the movieclips radius (since a circle is round we half its width to get the radius)
    Code:
    function checkCircleCollision(c1, c2) {
    	//get the radius
    	var radius = (c1._width/2)+(c2._width/2);
    	//get the x distance
    	var dx = c1._x-c2._x;
    	//get the y distance
    	var dy = c1._y-c2._y;
    	//get the overall distance
    	var distance = Math.sqrt(dx*dx+dy*dy);
    	//return a boolean indicating whether the distance is less than the radius
    	return distance<radius;
    }
    onEnterFrame = function () {
    	circle1._x += 2;
    	circle2._x -= 2;
    	//check the collision between both circles
    	if (checkCircleCollision(circle1, circle2)) {
    		trace("hit");
    	}
    };
    The above code assumes two movieclips have the names “circle1” and “circle2”. And both movieclips are centered around their origin's


    Hopefully this has helped you, I’ve only covered some basic collision detection and responses, there are many ways to do them. These methods are generally not suited to tile based games and games which require realistic reaction. If your looking for such things, I suggest you try these links:

    Mathematical: http://www.moor47.fsnet.co.uk/gamephysics.htm

    Tile Based: http://www.tonypa.pri.ee/tbw/index.html

    More HitTest: http://board.flashkit.com/board/show...Test+explained
    Last edited by mr_malee; 09-10-2006 at 08:02 PM.
    lather yourself up with soap - soap arcade

  2. #2
    Who needs pants? hooligan2001's Avatar
    Join Date
    Apr 2001
    Location
    Somewhere
    Posts
    1,976
    Very Great resource mate, you were getting sick of hitTest questions to i guess


    Vote 1 to make this a sticky

  3. #3
    Senior Member tonypa's Avatar
    Join Date
    Jul 2001
    Location
    Estonia
    Posts
    8,223
    Added this to knowledge base.

    My comments:
    hitest can find a collision between two movieclips or two points against a movieclip
    Wrong. It can find collision between 1 point against movie clip.

    var speed = 10
    player._y += speed;
    if (landscape.hitTest(player._x, player._y, true)) {
    player._y -= speed;
    }
    Actually I find the example bad. There is no need to move movie clip, hittest and then move the movie clip back. Because you can use numbers instead of coordinates you should use it like this:
    Code:
    var speed = 10
    if (!landscape.hitTest(player._x, player._y+speed, true)) {
    	player._y += speed;
    }
    if (typeof enemy == "movieclip") {
    I have never used typeof so I dont see much use for it. First of, I think it is bad idea to place anything other then enemy movie clips in enemyparent holder clip. But if you really must fill it useless junk, then hittesting with variable or function returns false anyway. Overall, I feel bringing typeof into the example only confuses the idea.

    The above code assumes two movieclips have the names “circle1” and “circle2”.
    The code also assumes graphics in both circles are centered into registration point. What if your circles have graphics aligned to the left?

    You also should at least mention BitmapData.hitTest method which is different from the hittest you describe.

  4. #4
    Hey Timmy!!! walsher's Avatar
    Join Date
    Jan 2005
    Location
    Latrobe, PA
    Posts
    1,899
    Got a quick question about the hitTest with the shapeflag thingy. How does that one work? I've mainly used the plain hitTest. I see that it takes it's object x and y numbers.

    For instance, say you make a hill and I'd use the character for the hitTest to see if it'll go up the hill. I'm guessing that's what the shapeflag does? Thanks

  5. #5
    M.D. mr_malee's Avatar
    Join Date
    Dec 2002
    Location
    Shelter
    Posts
    4,139
    thanks for the advice tony, i've updated the post. Never really wrote a help resource before and it probably shows as with "typeof" i'm using that because whenever you run a "for in" loop within a movieclip it doesn't just list movieclips within the parent movieclips but variables and objects as well. I guess i should explain the typeof better.

    walsher, yes thats what a shapeflag can be used for.
    lather yourself up with soap - soap arcade

  6. #6
    Senior Member UnknownGuy's Avatar
    Join Date
    Jul 2003
    Location
    Canada
    Posts
    1,361
    That's when you break out some assetPropFlags, mr_malee .

    Nice contribution.

  7. #7
    Animal Lover, Flash lover eaglevision's Avatar
    Join Date
    Jan 2008
    Location
    In FlashKit
    Posts
    286
    I needed this ages ago!
    Thank you for this!
    I am glad this is a sticky!
    ~11-year old flasher

  8. #8
    Junior Member
    Join Date
    Apr 2008
    Posts
    4
    Would you please explain where and how do you use code for multiple instance collisions?
    Your example is very brief and doesn't tell where code goes, nor which variables need replacing with own instance names?

  9. #9
    M.D. mr_malee's Avatar
    Join Date
    Dec 2002
    Location
    Shelter
    Posts
    4,139
    that stuff is very specific to your game. I just outlined a simple structure which doesn't invlove arrays. But the code should be placed on the root of your movie.

    It should really be changed to use arrays, so it makes sense a little more. (with custom data). Maybe someone else can help you out now. I'm a little busy.
    lather yourself up with soap - soap arcade

  10. #10
    Junior Member
    Join Date
    Apr 2008
    Posts
    1

    Displaying variables on collision

    I am currently stuck in a project wherein I have created 2 shapes using action script and the main goal was if shape1 collides with shape2-shape2's height & width are displayed on a label.. Is it possible to retrieve shape2 variables when shape1 collides with it?Pls help i really don't know what to do next.....

  11. #11
    Member
    Join Date
    Sep 2003
    Location
    Brazil
    Posts
    49

    Lightbulb [as2] Collision Detection

    Hi.
    I´d like to know how to make a collision detection method for two movieclips with complex shapes. These two movieclips are child movieclips inside parent movieclips. I´ll call each parent movieclip as obj1 and obj2. So:

    Here we have our two objects (movieclips) with its child clips:

    _root.obj1.child
    _root.obj2.child

    How to make a collision detection method that would check the collision between the two child movieclips? And those child clips are not circules, they are shapes with complex format. I think I´d need a bitmap.hitTest or something like that, to test it. And, _root.obj1.child and _root.obj2 rotate on onEnterFrame what gets more complicated. As far as I know, I´d have to work with some matrix. Well, I don´t know matrix methods of use very well.
    I know that if you want a precise collision detection of a object that rotates you should use matrix, but I don´t know how.
    Tonypa, do you know how to do it?

    Just for us to realize it better...it would be something like this:

    Code:
    function checkCollision(a:MovieClip, b:MovieClip):Boolean{
        //Here I believe I´d have to make a localToGlobal for the child movieclip
       var aCoord = {x:a._x, y:a._y}
       a._parent.localToGlobal(aCoord)
       var aPoint:Point = new Point(aCoord.x, aCoord.y)
       var bPoint:Point = new Point(b._x, b._y)
       var boolean:Boolean = a.hitTest(aPoint, 1, b, bPoint, 1)
       return boolean
    }
    
    onEnterFrame=function(){
        obj1.child._rotation +=3
        obj2._rotation -=3
        if(checkCollision(obj1.child, obj2)){
             trace("hit")
        }else{
             trace("no hit")
        }
    }
    I believe that the big problem here is:
    _root.obj1.child rotate and obj2 rotate. So how can I do it?

    Thanks

  12. #12
    Please, Call Me Bob trogdor458's Avatar
    Join Date
    Aug 2006
    Location
    Pensacola, FL
    Posts
    915
    Unless a shape-to-shape function was made that I'm unaware of, I know of 4 ways to do complex shape collisions

    1) A big loop that tests many coordinates against both shapes using the shape flag; if a point is found that hits both, then the objects hit each other
    2) Storing the vector information yourself, and using math to figure out intersections (this would be like creating your own shape-to-shape function, while suffering some speed/functionality)
    3) If one of the shapes is convex, and your shapes aren't dynamic, there's a trick you can do that will use a single hitTest with the shape flag
    4) There's another trick that employs bitmaps I think to check for collisions, and this may be your best option as I've seen it discussed here before

    I could go in depth depending what option you want to go with

    The reason I think a shape-to-shape function hasn't been programmed into flash is because they do want to use math (it's the most accurate of methods I listed), but I think vector images can be drawn using up to cubic beziers, and solving for its interaction with other cubic beziers has no general solution, and thus blah blah blah blah....

  13. #13
    Member
    Join Date
    Sep 2003
    Location
    Brazil
    Posts
    49

    Thumbs up [as2] Collision Detection

    I use to do with bitmap.hitTest.
    But if you have a lighter way to do it (a way that doesn´t use too much processing), better.
    Just for you to know that, with bitmap.hitTest I don´t know a way that works, when the two movieclips that are used to test collision are rotating.

    The shape of the objects I´m using are complex, their shape are close of a star shape.

    I don´t want the way of inserting lots of empty movieclips inside a movieclip for testing points.
    If you have another way...better.
    Thanks
    Last edited by marcelozep; 07-23-2010 at 03:31 PM.

  14. #14
    Please, Call Me Bob trogdor458's Avatar
    Join Date
    Aug 2006
    Location
    Pensacola, FL
    Posts
    915
    Right, looks like that function was made with AS3 and I just didn't catch it
    Seems completely viable

    Let's say you have two movieclips on stage in all their vectory goodness
    You can use the draw method just fine, the only problem being that the two images will be drawn relative to their own perspective
    This can lead to the bitmap being cropped where it ought not be, or the image not being rotated correctly
    This means you'll have to make sure the image is between the 0,0 point and whatever width/height you've applied to your bitmaps, and if you want to rotate the image, best rotate the image inside the movieclip instead of the entire movieclip itself

    And since you said stars...

    Code:
    import flash.display.BitmapData;
    import flash.geom.Point;
    import flash.display.Bitmap;
    
    hit1.x=mouseX-39;
    hit1.y=mouseY-39;
    hit1.star.rotation++
    var bit1,bit2:BitmapData;
    bit1=new BitmapData(100,100,true,0);
    bit2=new BitmapData(100,100,true,0);
    bit1.draw(hit1);
    bit2.draw(hit2);
    if(bit1.hitTest(new Point(hit1.x,hit1.y),0x80,bit2,new Point(hit2.x,hit2.y))){
    	hit1.star.gotoAndStop(2);
    }else{
    	hit1.star.gotoAndStop(1);
    }
    On the stage are two moveclips called "hit1" and "hit2", and inside them are star moveclips called "star" with 2 frames consisting of being purple and red

    I made sure the 100x100 bitmap boxes were big enough to always capture the rotating star

    And, yeah... is quick example, I don't know how good of quality that was

  15. #15
    Member
    Join Date
    Sep 2003
    Location
    Brazil
    Posts
    49

    Thumbs up [as2] Collision Detection

    Hey .
    Thanks.
    I´ll take a look.


  16. #16
    Member
    Join Date
    Sep 2003
    Location
    Brazil
    Posts
    49
    Quote Originally Posted by trogdor458 View Post
    Right, looks like that function was made with AS3 and I just didn't catch it
    Seems completely viable

    Let's say you have two movieclips on stage in all their vectory goodness
    You can use the draw method just fine, the only problem being that the two images will be drawn relative to their own perspective
    This can lead to the bitmap being cropped where it ought not be, or the image not being rotated correctly
    This means you'll have to make sure the image is between the 0,0 point and whatever width/height you've applied to your bitmaps, and if you want to rotate the image, best rotate the image inside the movieclip instead of the entire movieclip itself

    And since you said stars...

    Code:
    import flash.display.BitmapData;
    import flash.geom.Point;
    import flash.display.Bitmap;
    
    hit1.x=mouseX-39;
    hit1.y=mouseY-39;
    hit1.star.rotation++
    var bit1,bit2:BitmapData;
    bit1=new BitmapData(100,100,true,0);
    bit2=new BitmapData(100,100,true,0);
    bit1.draw(hit1);
    bit2.draw(hit2);
    if(bit1.hitTest(new Point(hit1.x,hit1.y),0x80,bit2,new Point(hit2.x,hit2.y))){
    	hit1.star.gotoAndStop(2);
    }else{
    	hit1.star.gotoAndStop(1);
    }
    On the stage are two moveclips called "hit1" and "hit2", and inside them are star moveclips called "star" with 2 frames consisting of being purple and red

    I made sure the 100x100 bitmap boxes were big enough to always capture the rotating star

    And, yeah... is quick example, I don't know how good of quality that was
    I don´t know if it matters. The child movieclips have registration point at the center of the movieclip.
    And both hit1.star rotates and hit2 rotates.

    Can you code it again?
    I´ve tried here and it doesn´t work with this settings.

  17. #17
    Please, Call Me Bob trogdor458's Avatar
    Join Date
    Aug 2006
    Location
    Pensacola, FL
    Posts
    915
    Well the code's solid, if you have at least CS4 you can look at the source directly (I hate limited reverse-compatibility), though I can't imagine your trouble with recreating it

    And it doesn't matter how the child movieclips look as long as the parent movieclips are set-up right
    Even if you resize the parents, move them, or rotate them, etc. the content inside them will still be drawn as if though nothing was changed, in this case from (0,0) to (100,100), so don't do anything to them

    If you want both stars rotating in this example, just put in
    hit2.star.rotation--
    as well
    Attached Files Attached Files

  18. #18
    Member
    Join Date
    Sep 2003
    Location
    Brazil
    Posts
    49

    [as2] Collision Detection

    Yes the code works.
    But what if I change the hit1 registration point to the center?
    Then, the code doesn´t work.
    Can you fix it?

  19. #19
    Please, Call Me Bob trogdor458's Avatar
    Join Date
    Aug 2006
    Location
    Pensacola, FL
    Posts
    915
    Why would you need to?
    I already counteracted the only two reasons I could think to need to it in the example:

    I might've needed it centered so the star would rotate correctly, but I centered the child movieclip instead
    I might've needed it centered so it would follow the cursor better, but I just offset it instead with the "mouseX-39", etc.

  20. #20
    Member
    Join Date
    Sep 2003
    Location
    Brazil
    Posts
    49

    [as2] Collision Detection

    Believe me I need the registration point of hit1 on the center and I need it to rotate .
    Yes, that´s right.
    But, there´s a but.
    Inside hit1 I have two movieclips. One movieclip I want to test collision detection, the ship movieclip. The other
    I don´t want to, the fire thrust. They compose a draw. But I´d only want to test
    the ship.
    So, hit1 is a ship with its thrust fire.
    I need hit1 center registration point so I can rotate it both.
    Last edited by marcelozep; 07-24-2010 at 09:28 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center