Resolving bounding box collision detection
- by ndg
I'm working on a simple collision detection and resolution method for a 2d tile-based bounding box system. Collision appears to work correctly, but I'm having issues with resolving a collision after it has happened.
Essentially what I'm attempting to do is very similar to this approach. The problem I'm experiencing is that because objects can be traveling with both horizontal and vertical velocity, my resolution code causes the object to jump incorrectly.
I've drawn the following annotation to explain my issue. In this example, because my object has both horizontal and vertical velocity, my object (which is heading upwards and collides with the bottom of a tile) has it's position altered twice:
To correctly adjust it's vertical position to be beneath the tile.
To incorrectly adjust it's horizontal position to be to the left of the tile.
Below is my collision/resolution code in full:
function intersects(x1, y1, w1, h1, x2, y2, w2, h2)
{
w2 += x2;
w1 += x1;
if (x2 > w1 || x1 > w2) return false;
h2 += y2;
h1 += y1;
if (y2 > h1 || y1 > h2) return false;
return true;
}
for(var y = 0; y < this.game.level.tiles.length; y++)
{
for(var x = 0; x < this.game.level.tiles[y].length; x++)
{
var tile = this.game.level.getTile(x, y);
if(tile)
{
if(
this.velocity.x > 0 &&
intersects(this.position.x+dx+this.size.w, this.position.y+dy, 1, this.size.h, x*tileSize, y*tileSize, tileSize, tileSize)
)
{
this.position.x = ((x*tileSize)-this.size.w);
hitSomething = true;
break;
}
else if(
this.velocity.x < 0 &&
intersects(this.position.x+dx, this.position.y+dy, 1, this.size.h, x*tileSize, y*tileSize, tileSize, tileSize)
)
{
this.position.x = ((x*tileSize)+tileSize);
hitSomething = true;
break;
}
if(
this.velocity.y > 0 &&
intersects(this.position.x+dx, this.position.y+dy+this.size.h, this.size.w, 1, x*tileSize, y*tileSize, tileSize, tileSize)
)
{
this.position.y = ((y*tileSize)-this.size.h);
hitSomething = true;
break;
}
else if(
this.velocity.y < 0 &&
intersects(this.position.x+dx, this.position.y+dy, this.size.w, 1, x*tileSize, y*tileSize, tileSize, tileSize)
)
{
this.position.y = ((y*tileSize)+tileSize);
hitSomething = true;
break;
}
}
}
}
if(hitSomething)
{
this.velocity.x = this.velocity.y = 0;
dx = dy = 0;
this.setJumping(false);
}