I'm developing a Zelda game with Java using the Slick2d library.
I'm using the Separating Axis Theorem based algorithm for resolving collisions and it works pretty well. But as I use invisible polygon tiles as static collision objects, I am stuck with the famous "crack" problem, as described here:
Collision Detection with SAT: False Collision for Diagonal Movement Towards Vertical Tile-Walls?
Because of this problem, I decided to disable the static polygons' uncollidable edges which were used to determine a normal projection axis for SAT testing. By "uncollidable" I mean edges who are shared by multiple polygons. And for testing/debugging purposes, I made it so the game draws every polygon's every edge.
But it doesn't draw only the general shape as expected, it still draws ALL the edges: that means the "uncollidable" edges are still used for collisions, and that's what I don't want!
Here is the code for the SAT projection axes for polygons:
public Vector2f[] getAxes(Shape myShape){
if(uselessEdgesDefined==false){
ArrayList<Vector2f> _tmpList=new ArrayList<>();
for(int i=0;i<myShape.getPointCount();i++){
Vector2f p1=new Vector2f(myShape.getPoint(i)[0],myShape.getPoint(i)[1]);
int k;
if(i==myShape.getPointCount()-1){
k=0;
}else{
k=i+1;
}
Vector2f p2=new Vector2f(myShape.getPoint(k)[0],myShape.getPoint(k)[1]);
boolean yes=true;
for(int ii=0;ii<Map.SolidsList.size();ii++){
if(Map.SolidsList.get(ii).myCollisionPolygon!=this){
if(DefineEdgeUseless(p1, p2, Map.SolidsList.get(ii).myCollisionPolygon.myPolygon)){ //Testing if current edge is shared with other polygons
yes=false; //Yes, this edge is shared with other polygons!
break;
}
}
}
if(yes==true){ // If the current edge has not been flagged as being shared with other polygons, use it to get the projection axis.
Vector2f edge=p1.sub(p2);
Vector2f normal=edge.getPerpendicular();
_tmpList.add(normal);
//The problem is that it looks like this block is always executed as all the edges are visible, even if "yes" has been set to false.
}
}
axesToProjectOn=new Vector2f[_tmpList.size()];
axesToProjectOn=_tmpList.toArray(axesToProjectOn);
uselessEdgesDefined=true;
}
return axesToProjectOn;
}
public boolean DefineEdgeUseless(Vector2f A1,Vector2f A2,Shape B){
for(int i=0;i<B.getPointCount();i++){
Vector2f p1=new Vector2f(B.getPoint(i)[0],B.getPoint(i)[1]);
int k;
if(i==B.getPointCount()-1){
k=0;
}else{
k=i+1;
}
Vector2f p2=new Vector2f(B.getPoint(k)[0],B.getPoint(k)[1]);
if((A1.x==p1.x && A1.y==p1.y && A2.x==p2.x && A2.y==p2.y)
^(A2.x==p1.x && A2.y==p1.y && A1.x==p2.x && A1.y==p2.y)){ //The line formed by the 2 points is the same as another polygon's edge
return true;
}
}
return false;
}
I really can't figure out what is the problem in the code. I would really appreciate if someone could help with this code, or suggest other ways of avoiding the "crack" problem.
I hope I have been clear enough explaining the problem, I'm sorry if I wasn't: English is not my first language.
Thanks for taking a look!