PDA

View Full Version : hitTest vs. SAT (Enjoying Collision Detection)



EasternSquirrel
July 29th, 2006, 07:40 PM
definitions
==============
SAT - (seperating axis theorem) used by Metanet.com for their flash game "N". Advanced uses of this are commonly used in modern games.
hitTest - Commonly used in flash game design as a method of collision detection. Advanced use is rather slow and requires too much memory and processing speed.
==============

This is just the Basics of SAT. All of this has been created as a result of what I have learned from the MetaNet site, and other sites such as, Kirupa, FlashKit, Tutorialized, and Actionscript.org. Everything You really need to Know about why I did what is explained below in the "SAT" function
This code is free to you to learn from and adapt to your own needs as you use it, All I ask is that if you do Find a new use for this code or ways to make this code better, Tell me. My Email Address is: FlashSquirrel@hotmail.com, or add it to this post so others can benifit by you discovery. Also When you email me, ask for a copy of my game which I used this code in. Enjoy!

downlaod the .as version of the following code:

38150

================

SATReqs = function (guy, callThis) {
gx = _root.guy._x;
gy = _root.guy._y;
ghx = _root.guy._width/2;
ghy = _root.guy._height/2;
//
tx = callThis._x;
ty = callThis._y;
thx = callThis._width/2;
thy = callThis._height/2;
//GET ALL INFO.... DONE!
if (tx<gx+40) {
if (tx>gx-40) {
if (ty<gy+40) {
if (ty>gy-40) {
cb_y = thy+ghy;
dy = Math.abs(gy-ty)-cb_y;
cb_x = thx+ghx;
dx = Math.abs(gx-tx)-cb_x;
if (dx<0) {
if (dy<0) {
_root.guy.hit = true;
} else {
_root.guy.hit = false;
}
} else {
_root.guy.hit = false;
}
}
}
}
}
};
//----------------
//----------------
//on the MovieClip you Want to test with the above code!
onLoad = function () {
hit = false;
//NOT ALWAYS NECESSARY, but it prevents the chance of any errors w/ undefined Variables.
};
onEnterFrame = function () {
SATReqs(this, wall);
if (hit) {
//Result of Collision!
}
};
//----------------
//----------------
//Variation to act as walls to a given object...
SAT = function (guy) {
gx = _root.guy._x;
gy = _root.guy._y;
ghx = _root.guy._width/2;
ghy = _root.guy._height/2;
//note: all walls in the current screen are identified under the "bounds" Array
for (tt=0; tt<bounds.length; tt++) {
//Using this allows Flash find all WAlls At once, then if they are close enough, then check if there is contact.
temp = bounds[tt];
tx = temp._x;
ty = temp._y;
thx = temp._width/2;
thy = temp._height/2;
//GET ALL INFO.... DONE!
if (tx<gx+40) {
if (tx>gx-40) {
if (ty<gy+40) {
if (ty>gy-40) {
//The following code is based on the ACTUAL [seperating axis theorem] by MetaNet
// dist = squareRoot of( (X1-X2)^2 + (Y1-Y2)^2 ) [^2 means Squared]
//--------------------
//dist between the two objects according to the Y-axis, Subtracted by the Y Half-Width of the WALL[cb_y]
cb_y = thy+ghy;
dy = Math.abs(gy-ty)-cb_y;
//-------------------
//dist between the two objects according to the X-axis, Subtracted by the X Half-Width of the WALL[cb_x]
cb_x = thx+ghx;
dx = Math.abs(gx-tx)-cb_x;
//
if (dy<=0) {
if (dx<=0) {
//To understand this better, look around online for a bit of code for objects rotating to face your mouse.
//This in the similar code but applied to a different principle.
//First, It determines Radians between TEMP and GUY.
//Then converts it into degrees...
//the "/90)*90" is used with the MATH.ROUND to convert the RESULT into increments of 90 degrees.
//So there is a possiblity of following directions only. (0 degrees, 90 degrees, 180 degrees, -90 degrees, -180 degrees)
myRadians = Math.atan2(temp._y-guy._y, temp._x-guy._x);
myDegrees = Math.round(Math.round((myRadians*180/Math.PI))/90)*90;
// by subtracting 90 the starting point for the degrees is set for better use.
lhc = myDegrees-90;
xSpeed = Math.abs(dx)*Math.sin(lhc*(Math.PI/180));
ySpeed = Math.abs(dy)*Math.cos(lhc*(Math.PI/180));
guy._y -= ySpeed;
guy._x += xSpeed;
//The rest is used to move "guy" the correct direction and distance away from the Center of the WALL the guy is touching.
}
}
}
}
}
}
}
};
//----------------
//----------------
//on the MovieClip you Want to test with the above code!
onEnterFrame = function () {
SAT(this);
//Much Simplier! :thumb2:
};
//----------------
//----------------


=============

Hey, once you have tried it, post:
1. What you think of it!
2. Ways to improve it.
3. Other uses for this code.

badmonur
July 29th, 2006, 08:03 PM
jesus christ man. That is really complicated, to tell teh truth i only understood the first 10-20 lines, the rest is a blur

EasternSquirrel
July 29th, 2006, 09:13 PM
Sorry. this is really all you need. If this is easier to understand.

-put this code into the object you want to be your Main Guy.
onEnterFrame = function () {
SAT(this, _root.wall);
};

-put this code in frame 1 of the Movie.
SAT = function (guy, wall) {
gx = _root.guy._x;
gy = _root.guy._y;
ghx = _root.guy._width/2;
ghy = _root.guy._height/2;
temp = wall;
tx = temp._x;
ty = temp._y;
thx = temp._width/2;
thy = temp._height/2;
cb_y = thy+ghy;
dy = Math.abs(gy-ty)-cb_y;
cb_x = thx+ghx;
dx = Math.abs(gx-tx)-cb_x;
if (dx<0) {
if (dy<0) {
_root.guy.hit = true;
} else {
_root.guy.hit = false;
}
} else {
_root.guy.hit = false;
}
};


then place a movieClip called "wall" on the screen.
Ta-da. it should be all you need.

Lord Impero
July 29th, 2006, 10:00 PM
^OK will try that and sounds good.
BTW thats a really short version than te first one

Lord Impero
July 30th, 2006, 04:18 AM
OK find dude this is going to sound so dumb but I am unable to use your code.....
Could you please put up an fla?

biznuge
July 30th, 2006, 07:00 AM
this doesn't work by the way!

Sorry... It does actually work as a basic hit test, but if you use an irregularly shaped object for either of the testees, then you get results which don't correspond to the actual overlap.

I can't quite see what the point of this function is, since it's already there in AS core functionality???

Unless maybe i'm missing your point with this, and you are specifically TRYING to lose any kind of true collision detection with this function???

Sorry to beatch, but I would be interested in the response whatever! ;)

biznuge
July 30th, 2006, 07:03 AM
And heres the FLA of what I was testing!

Lord Impero
July 30th, 2006, 08:34 AM
^ thats it? i thought it was a wall script?:egg:
anyone knows how to use the SAT thing as a wall?

EasternSquirrel
July 30th, 2006, 11:59 AM
Congrats, I was wondering when someone would notice that the code was designed for walls. By the way, that's what I intended it for.

The large amount of code in the original post, with the comments in it, is a wall code, so far above hitTest, (it still is limited to square objects at this time, sorry) but it works so much better for creating walls or solid objects in games, Also it does not lag at all with 500+ objects to test against on the screen. The SHORT VERSION will after about 40

note:
"SAT = function () {}" is the same as "function SAT {}"

If you want a copy of my game I used this code in, Email me at: flashsquirrel@hotmail.com
(it is a beta version, so there are things not yet finished)

I would post it here but the file size is too big

biznuge
July 30th, 2006, 06:00 PM
Also it does not lag at all with 500+ objects to test against on the screen. The SHORT VERSION will after about 40

Could you explain exactly how you tested this, with 500 objects on screen at one time, and what code went into the 500 objects that you were working with?

I've kinda got a Schrodinger's Cat kinda problem in my head with someone telling me something like that. When I can't quite work out how you'd scientifically assess this without introducing extra coding (and hence extra processor time) into the equation!!!

I'm not trying to catch anyone out here easternsquirrel, but some answers would be great!

EasternSquirrel
July 30th, 2006, 11:12 PM
Well, the reason it does not lag is that you are only testing the area, within 40 units of the actual guy's center.

if (tx<gx+40) {
if (tx>gx-40) {
if (ty<gy+40) {
if (ty>gy-40) {
}}}}

So really any number of objects will not be effected at all. And yes I have done around 550 wall segments and other interactive objects in my game at once and it did not lag at all, even on Flash Player 7 and 6.

badmonur
July 31st, 2006, 12:44 AM
this dusth hurtith my brainith. I guess i will understand it in time when i become a bit more skilled.;)

EasternSquirrel
August 4th, 2006, 03:47 AM
Hey, for those of you who want a hit test that does Circles.

Hoo-Yah!
I just got it to Work View the .SWF and .FLA!

On the SWF, the green ball moves with the Arrow Keys and Shrinks with PGDN, and Grows with PGUP! And the green ball Never Enters the Blue Ball, See for yourself!

38297 (updated as of 01:20 am)

This is sweet and smooth.

Here's the code:

SAT = function () {
gx = _root.ball._x;
gy = _root.ball._y;
tx = _root.opp._x;
ty = _root.opp._y;
cb_y = ty-gy;
cb_x = tx-gx;
rd = Math.sqrt(cb_y*cb_y+cb_x*cb_x)-(_root.ball._width+_root.opp._width)/2
if (rd<=0) {
myRadians = Math.atan2(_root.opp._y-_root.ball._y, _root.opp._x-_root.ball._x);
myDegrees = Math.floor(myRadians*180/Math.PI)*1;
lhc = myDegrees-90;
xSpeed = Math.abs(rd)*Math.sin(lhc*(Math.PI/180));
ySpeed = Math.abs(rd)*Math.cos(lhc*(Math.PI/180));
_root.ball._y -= ySpeed;
_root.ball._x += xSpeed;
}
};

EasternSquirrel
August 4th, 2006, 04:22 AM
What do you think of this code? Compared the the previous SAT code for Squares?

biznuge
August 4th, 2006, 04:44 AM
Works quite well squirrel. I can see this could be useful to you if you were purely using circular objects in a project.

What I actually meant by "irregular objects" was shapes etc. but I have to admit this code is rather neat!

If you don't mind, I'd like to re-use it for a small project, just to test the water with it...? Full credit for your function(); No problem if it's a hands off though! :rabbit:

EasternSquirrel
August 4th, 2006, 04:54 AM
Feel Free to use it. If you want to give me credit, thanks, I respect that.

biznuge
August 4th, 2006, 05:25 AM
no problem mate! Dunno when the hell I'll get a chance to take a gander at it, but I'll try and find some time soon!:hr:

Lord Impero
August 4th, 2006, 09:41 AM
Cool! Thanks to both of you!:D
*Names given credit*