@azrafe7 your hxGeomAlgo is awesome! It was really really handy for me. I would take a lot of time to implement polygon decomposition myself, and this saved me a lot of time. And the best thing is that you can automatically get the points of a polygon from a png. This was the next thing I would have to see, and your lib had it, that’s really nice. It’s working nicely.
I’ll post my SAT here, since you want to see. Most of the code is based on this article. The only lib I’m using is a Vec2 lib. Please feel free to point any mistake I could have done.
/**
* Returns true if two polygons overlap. The polygon must be given as an Array of Points (flash.geom.Point).
* @param poly1 The first polygon.
* @param poly2 The second polygon.
*/
public function sat(poly1:Array, poly2:Array):Boolean {
var currVertex:Point, nextVertex:Point, axis:Vec2, proj1:Array, proj2:Array;
//test all the edges of the first polygon
for ( var i1:int = 0; i1 < poly1.length; i1++) {
currVertex = poly1[i1] as Point;
nextVertex = i1 == poly1.length - 1? poly1[0] as Point:
poly1[i1 + 1] as Point;
//direction the current edge is pointing at
axis = new Vec2(currVertex.x - nextVertex.x, currVertex.y - nextVertex.y);
axis.perpLeftSelf();
//projections of both polygons
proj1 = project(poly1, axis);
proj2 = project(poly2, axis);
//if the two projections are not overlapping, the polygons are not overlapping
if( ! overlap(proj1, proj2) ){
return false;
}
}
//teste all teh edges of the second polygon
for ( var i2:int = 0; i2 < poly2.length; i2++) {
currVertex = poly2[i2] as Point;
nextVertex = i2 == poly2.length - 1? poly2[0] as Point:
poly2[i2 + 1] as Point;
//direction the current edge is pointing at
axis = new Vec2(currVertex.x - nextVertex.x, currVertex.y - nextVertex.y);
axis.perpLeftSelf();
//projections of both polygons
proj1 = project(poly1, axis);
proj2 = project(poly2, axis);
//if the two projections are not overlapping, the polygons are not overlapping
if( ! overlap(proj1, proj2) ){
return false;
}
}
//if no projections are separated, the polygons are colliding
return true;
}
/**
* Returns true if a polygon and a circle overlap. The polygon must be given as an Array of Points (flash.geom.Point).
* For the circle, a center point and a radius must be given.
* @param poly The polygon.
* @param circleCenter The center point of the circle.
* @param circleRadius The radius of the circle.
*/
public function circleSat(poly:Array, circleCenter:Point, circleRadius:Number):Boolean {
var currVertex:Point, nextVertex:Point, axis:Vec2, proj1:Array, proj2:Array;
//test all the edges of the polygon.
for ( var i1:int = 0; i1 < poly.length; i1++) {
currVertex = poly[i1] as Point;
nextVertex = i1 == poly.length - 1? poly[0] as Point:
poly[i1 + 1] as Point;
//direction the current edge is pointing at
axis = new Vec2(currVertex.x - nextVertex.x, currVertex.y - nextVertex.y);
axis.perpLeftSelf();
//projection of the polygon
proj1 = project(poly, axis);
//projection of the circle
proj2 = projectCircle(circleCenter, circleRadius, axis);
//if the two projections are not overlapping, the polygon and the circle are not overlapping
if( ! overlap(proj1, proj2) ){
return false;
}
}
//get also the axis that points from the circle to the closest vertex
var closest:Point = closestVertex(poly, circleCenter);
axis = new Vec2(closest.x - circleCenter.x, closest.y - circleCenter.y);
//and see if the projections on that vertex overlap
if( ! overlap(project(poly, axis), projectCircle(circleCenter, circleRadius, axis)) ){
return false;
}
//if no projections are separated, the circle and the polygon are overlapping.
return true;
}
//projects a polygon
private function project(poly:Array, axis:Vec2):Array {
axis.normalizeSelf();
var min:Number = axis.dotXY( (poly[0] as Point).x, (poly[0] as Point).y );
var max:Number = min;
var proj:Number = 0;
for each( var p:Point in poly ){
proj = axis.dotXY(p.x, p.y);
if(proj < min){
min = proj;
}
if(proj > max){
max = proj;
}
}
return new Array(min, max);
}
//projects a circle
private function projectCircle(circleCenter:Point, circleRadius:Number, axis:Vec2):Array {
var centerDot:Number = axis.dotXY( circleCenter.x, circleCenter.y );
return new Array(centerDot - circleRadius, centerDot + circleRadius);
}
//returns the closest vertex to a circle
private function closestVertex(poly:Array, cirlceCenter:Point):Point {
var distance:Number = Number.MAX_VALUE;
var closest:Point;
for each (var p:Point in poly){
var testDistance:Number = eDistance(p.x, p.y, cirlceCenter.x, cirlceCenter.y);
if( testDistance < distance){
distance = testDistance;
closest = p;
}
}
return closest;
}
//returns true if a point is between two other points, in an unidimensional space
private function contains(n:Number, range:Array):Boolean {
return n >= range[0] && n <= range[1];
}
//returns true if two projections are overlapping
private function overlap(proj1:Array, proj2:Array):Boolean {
if (contains(proj1[0], proj2) ) return true;
else if (contains(proj1[1], proj2) ) return true;
else if (contains(proj2[0], proj1) ) return true;
else if (contains(proj2[1], proj1) ) return true;
return false;
}
//euclidean distance
private function eDistance(x1:Number, y1:Number, x2:Number, y2:Number):Number {
return Math.sqrt( (x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) );
}
Also, thanks a lot for your sugestions @zachwlewis and @Ultima2876. I had already learned the concepts and all, but I was looking for something done already.