# Collision detection - make sure the player touches the object exactly

I know this is really something I should be able to figure out on my own, but a solution is evading me.

Okay, here are a few relevant parts of my code.

bool Game::Col(int x1,int y1,int w1,int h1, int x2, int y2,int w2,int h2)
{
if(x1 > x2 + w2 || y1 > y2 + h2 || x2 > x1 + w1 || y2 > y1 + h1)
{
return false;
}
return true;
}


That's my collision detecting algorithm. Simple, for rectangles only.

        int bX = (player.getX() - 64) / 32;
int bY = (player.getY() - 64) / 32;
int tX = (player.getX() + 64) / 32;
int tY = (player.getY() + 64) / 32;

for(int a=bX;a<tX;a++)
{
for(int b=bY;b<tY;b++)
{
if(Col(player.getX(), player.getY(), 32, 32, a * 32, b * 32, 32, 32) && blocks[a][b] == 1)
{
player.setX(oldX);
player.setY(oldY);
goto loopExit;
}
}
}

loopExit:


Here is my collision detection. This is performed right after the player x/y is manipulated(5 pixels in whatever direction every 1/60th of a second). Blocks is just a 2d array for my tile map. I know the way I have collision detection right now is not too optimized, but it took a few seconds to implement and is reasonably fast.

But the player can only get within 5 pixels of an object now. How do I solve that?

• What is the purpose of bX,bY,tX,tY ? Using clearly named variables makes it easier to understand code. Tip : if you are checking for blocks==1 means there is a block there, do it before Col() to save time. – karmington Feb 6 '14 at 22:10
• Because I have variables named what I wanted to name them verbosely, I'm planning on fixing that. I swear I don't usually do that. – user701329 Feb 6 '14 at 22:15
• Okay, I figured it out, you are checking for the nearest blocks. A line of comment saying so would speed up the reading. – karmington Feb 6 '14 at 22:22

What you need to do is create a method that gets the amount that the player overlaps the tile by. You would make a copy of this method for each axis. When you are moving the player, you first move the player on the X axis. Then you check for collision. If you find a colliding tile, you get the player's offset into the tile and subtract that from the player's X axis (note that you will have to account for the direction the player is moving).

After you have moved the player on the X axis, you repeat the process on the Y axis, getting the colliding tile and offsetting the player. There is a reason why we have to move on each axis independently. If we didn't do this, you wouldn't be able to tell which movement caused the collision. In other words, did the fact that we are falling cause the collision, meaning that we have to get the Y offset? Or was it because we are moving to the right?

With this knowledge in mind, our collision code should look something like this:

void movePlayer()
{
int left = // get the left-most tile to check for collision
int right = // get the right-most tile to check for collision
int top = // get the top-most tile to check for collision
int bottom = // get the bottom-most tile to check for collision

for(int xt = left; xt < right; xt++)
{
for(int yt = top; yt < bottom; yt++)
{
Tile t = world.getTile(xt, yt);
if(aabb.collidesWith(t.getBox())
{
xPos -= t.getBox().getOffsetX(aabb, /* Here you may also pass in the movement direction to determine wether you should pass
a positive or negative number, to ensure you move the player in the right direction. */);
}
}
}

aabb.updateBox(); // Because we moved the character. You may also want to update the left and right variables

for(int xt = left; xt < right; xt++)
{
for(int yt = top; yt < bottom; yt++)
{
Tile t = world.getTile(xt, yt);
if(aabb.collidesWith(t.getBox())
{
yPos -= t.getBox().getOffsetY(aabb, /* Again, pass the movement direction. I usually represent
this with a positive or negative integer. */);
}
}
}

aabb.updateBox();
}