Brady W Brady W - 13 days ago 5
Javascript Question

What's wrong with my AABB collision detection/resolution code?

I am working on a game engine in JavaScript, and i'm currently working on the collision system. I made an algorithm to resolve collisions detected with the player, but i'm not getting the intended behavior. Here is the code:

if (gameObjects [i].hasComponent ("BoxCollider") == true) {
for (var x = 0; x < gameObjects.length; x++) {
if (gameObjects [x].hasComponent ("BoxCollider") == true && gameObjects [i] != gameObjects [x]) {
if (gameObjects [i].transform.xPos - (gameObjects [i].getComponent ("BoxCollider").width / 2) < gameObjects [x].transform.xPos + (gameObjects [x].getComponent ("BoxCollider").width / 2) && gameObjects [i].transform.xPos + (gameObjects [i].getComponent ("BoxCollider").width / 2) > gameObjects [x].transform.xPos - (gameObjects [x].getComponent ("BoxCollider").width / 2) && gameObjects [i].transform.yPos - (gameObjects [i].getComponent ("BoxCollider").height / 2) < gameObjects [x].transform.yPos + (gameObjects [x].getComponent ("BoxCollider").height / 2) && gameObjects [i].transform.yPos + (gameObjects [i].getComponent ("BoxCollider").height / 2) > gameObjects [x].transform.yPos - (gameObjects [x].getComponent ("BoxCollider").height / 2)) {
//collision
if (gameObjects [i] == player) {

var xPenetration = 0;
var yPenetration = 0;

//i is left of x
if (gameObjects [i].transform.xPos < gameObjects [x].transform.xPos) {
xPenetration = -1 * ((/*i right edge*/gameObjects [i].transform.xPos + gameObjects [i].boxCollider.width / 2) - (/*x left edge*/gameObjects [x].transform.xPos - gameObjects [x].boxCollider.width / 2));
}

//i is right of x
else if (gameObjects [i].transform.xPos > gameObjects [x].transform.xPos) {
xPenetration = ((/*x right edge*/gameObjects [x].transform.xPos + gameObjects [x].boxCollider.width / 2) - (/*i left edge*/gameObjects [i].transform.xPos - gameObjects [i].boxCollider.width / 2));
}

//i is top of x
if (gameObjects [i].transform.yPos < gameObjects [x].transform.yPos) {
yPenetration = -1 * ((/*i bottom edge*/gameObjects [i].transform.yPos + gameObjects [i].boxCollider.height / 2) - (/*x top edge*/gameObjects [x].transform.yPos - gameObjects [x].boxCollider.height / 2));
}

//i is bottom of x
else if (gameObjects [i].transform.yPos > gameObjects [x].transform.yPos) {
yPenetration = ((/*x bottom edge*/gameObjects [x].transform.yPos + gameObjects [x].boxCollider.height / 2) - (/*i top edge*/gameObjects [i].transform.yPos - gameObjects [i].boxCollider.height / 2));
}

if (Math.abs (xPenetration) > Math.abs (yPenetration)) {
gameObjects [i].transform.xPos += xPenetration;
} else {
gameObjects [i].transform.yPos += yPenetration;
}

}
}
}
}
}
}

Answer

There's a couple of problems. Firstly, you need to handle the case where gameObjects [i].transform.xPos is exactly equal to gameObjects [x].transform.xPos (and same for the y position). At the moment you are handling less than and greater than but not equal. So just change the < to <= or the > to >= e.g:

if (gameObjects [i].transform.xPos <= gameObjects [x].transform.xPos)

The other problem is that when you collide, it looks more natural if you push an object out of the object it has collided with along the axis with the minimum penetration distance. So just change this line to select the min of x and y instead of the max:

if (Math.abs (xPenetration) < Math.abs (yPenetration))
Comments