# 2D collision resolution: works on each axis individually, but not with both combined

My collision detection method is solid and detects box to box collision every time. Then comes the resolve part which I'm struggling with quite a bit. It works perfectly when I'm manipulating the x-axis and y-axis of the player (tile) but only happens to work when I move on any given axis individually. If I try to move on both axis then the whole thing breaks down and starts acting weird.

I'm trying to implement gravity. And so I keep a constant down force on my player tile. This is when I realized that when I'm applying force on both axis (because gravity is constantly applying force on the y-axis) and moving the player tile right or left on the same time my collision resolve method breaks down.

My collision is working great while moving along each axis individually. Here's the result:

How can I approach collision resolution in order to avoid this type of result?

I'm currently predicting the position the player will be at, then I'm checking every single collideable tile at that position. If I detect a collision, I move the player back along the axis the collision was detected in.

This is my current code with collisions working well on a single axis at a time:

void Tile_Player::Move(double delta, G3::Tile_Map *map)
{
int xvel = (this->xDirection * (G3::TILE_STEP * (delta/1000)));
int yvel = (this->yDirection * (G3::TILE_STEP * (delta/1000)));

G3::xy_pos predictedPos;
predictedPos.x = this->tile_location.x; predictedPos.y = this->tile_location.y;

predictedPos.x += xvel;
predictedPos.y += yvel;

bool collision_status = false;

for (int i=0; i< map->GetTotalTileCount(); i++)
{
G3::Tile *tempTile = map->GetTileAt(i);
if (this != tempTile)
{
bool coll_bool;
coll_bool =  this->CheckCollision(predictedPos, tempTile->GetTilePos());
if (coll_bool)
{
//check collision on the left
if (this->xDirection == -1)
{
predictedPos.x = tempTile->GetTilePos().x+G3::TILE_SIZE+0.1;
}
//check collision on the right
if (this->xDirection == 1)
{
predictedPos.x = tempTile->GetTilePos().x-G3::TILE_SIZE-0.1;
}
//check collision on bottom(ground)
if (this->yDirection == -1)
{
predictedPos.y = tempTile->GetTilePos().y+G3::TILE_SIZE+0.1;
}
//check collision on top
if (this->yDirection == 1)
{
predictedPos.y = tempTile->GetTilePos().y-G3::TILE_SIZE-0.1;
}

}
}
}

this->tile_location.x = predictedPos.x;
this->tile_location.y = predictedPos.y;

this->xDirection = 0;
this->yDirection = 0;
}

• where are you adding gravity? adding velocity due to gravity to the predicted position before the collision detection should probably work fine if your CheckCollision function is working as expected. – gordonk Jun 17 '13 at 13:14
• I guess when we have a duplicate of a too localized question, maybe it wasn't too localized. gamedev.stackexchange.com/questions/35080/… – MichaelHouse Jun 17 '13 at 13:17
• i could add up: int this->yDirection = -1; at the very beginning of my function and i would have a constant "force" pulling me down. But then if i try to move right or left i would be applying two "forces" at once and hence my collision resolution breaks down. – apoiat Jun 17 '13 at 13:51
• i would then integrate states like is_ground=true if i have a top collision and is_ground=false if i have no collisions whatsoever but havent managed to work it out so far. Its possible im messing the logic behind it. – apoiat Jun 17 '13 at 13:53
• @Byte56: the question as it stands is too localized (debug his code), but it could be cleared up to be about general practice and math independent of a specific implementation. Especially as addressing this singular bug isn't going to fix any of the larger problems in his approach to platformer physics, this just isn't super useful in general as stated. – Sean Middleditch Jun 17 '13 at 17:44

## 1 Answer

In the part of your code where you use 'coll_bool' to check if there was a collision, I believe you also need to check if your object is colliding only on the X or Y axis.

For example if your object collides with a wall while falling (although there is Y movement it's only colliding in the X axis) you will still check for the Y direction (movement direction, which in this case does not mean there is a collision in that direction) and set the Y position to an unexpected value. I guess your object would instantly move 1 tile downwards.

Might this be your problem?

• i can see something here but it's possible im quite baffled. I do believe the error is somewhere in the logic. But am i not checking where the collision is happening right after checking if there is a collision in general? (coll_bool) – apoiat Jun 17 '13 at 14:07
• do you by any chance mean something like: i should add states like collisionXaxis and collisionYaxis booleans and integrate them in my coll_bool check? – apoiat Jun 17 '13 at 14:09
• You're checking if there's a general collision, but then you're going to check what's the movement direction on the object. And even though the collision may have occurred in only one of the axis, you'll update the position on the both axis (including the one that "did not collide"). I'd suggest that you check the X and Y collisions with separate conditions, although that still leaves one problem that is colliding with corners that I'm not so sure myself how to solve. – aslg Jun 17 '13 at 14:13
• I managed to solve my problem and my collision resolution is working flawlessly (for now). You both directed me in the right way and with a little bit more digging i found out i was already doing 90% of the work right but had that 10% wrong. What needed to happen after all was apply each velocity attribute individually and do the collision detection on each one of the axis. I also found this question/answer here ( gamedev.stackexchange.com/questions/30619/… ); which the selected answer was a spot on solution to my problem. – apoiat Jun 17 '13 at 21:42