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
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.....
[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
[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 :)
[as2] Collision Detection
Hey :).
Thanks.
I´ll take a look.
:)
[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?
[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.
:)