# My 2D collision code does not work as expected. How do I fix it?

I have a simple 2D game with a tile-based map. I am new to game development, I followed the LazyFoo tutorials on SDL. The tiles are in a bmp file, but each tile inside it corresponds to an internal number of the type of tile(color, or wall).

The game is simple, but the code is a lot so I can only post snippets.

`````` // Player moved out of the map
if((player.box.x < 0))
player.box.x += GetVelocity(player, 0);

if((player.box.y < 0))
player.box.y += GetVelocity(player, 1);

if((player.box.x > (LEVEL_WIDTH - DOT_WIDTH)))
player.box.x -= GetVelocity(player, 0);

if((player.box.y > (LEVEL_HEIGHT - DOT_HEIGHT)))
player.box.y -= GetVelocity(player, 1);

// Now that we are here, we check for collisions
if(touches_wall(player.box))
{
if(player.box.x < player.prev_x)
{
player.box.x += GetVelocity(player, 0);
}

if(player.box.x > player.prev_x)
{
player.box.x -= GetVelocity(player, 0);
}

if(player.box.y < player.prev_y)
{
player.box.y += GetVelocity(player, 1);
}

if(player.box.y > player.prev_y)
{
player.box.y -= GetVelocity(player, 1);
}
}

player.prev_x = player.box.x;
player.prev_y = player.box.y;
``````

Let me explain, `player` is a structure with the following contents

``````typedef struct {
Rectangle box; //Player position on a map(tile or whatever).
int prev_x, prev_y; // Previous positions
int key_press[3]; // Stores which key was pressed/released. Limited to three keys. E.g Left,right and perhaps jump if possible in 2D

int velX, velY; // Velocity for X and Y coordinate.

//Health
int health;
bool main_character;
uint32_t jump_ticks;
} Player;
``````

And `Rectangle` is just a typedef of `SDL_Rect`. `GetVelocity` is a function that according to the second argument, returns the velocity for the X or Y axis.

This code I have basically works, however inside the `if(touches_wall(player.box))` if statement, I have 4 more. These 4 if statements are responsible for detecting collision on all 4 sides(up,down,left,right). However, they also act as a block for any other movement.

Example: I move down the object and collide with the wall, as I continue to move down and still collide with the wall, I wish to move left or right, which is indeed possible(not to mention in 3D games), but remember the 4 if statements? They are preventing me from moving anywhere. The original code on the LazyFoo Productions website has no problems, but it was written in C++, so I had to rewrite most of it to work, which is probably where the problem comes from. I also use a different method of moving, than the one in the examples.

Of course, that was just an example. I wish to be able to move no matter at which wall I collide. Before this bit of code, I had another one that had more logic in there, but it was flawed.

-
Velocity should be positive when moving to the right and negative when moving to the left - so why do you switch between adding and subtracting it? To undo movement it should always be correct to subtract velocity from position. – Kylotan Dec 12 '12 at 18:48
That is not it, collision detection(at least mine) works by going back however much you went in. – farmdve Dec 12 '12 at 19:13
@farmdve: collision resolution moves objects that have collided. Collision detection only finds out if there is a collision, and where that collision is. I think you're also misusing "velocity" as it appears to be speed in your code; velocity is speed with a specific direction as well, hence Kylotan's comment (if you moved left by 5 units then your velocity would be <-5,0>, and subtracting that gives you a move to the right by < 5,0>). – Sean Middleditch Dec 12 '12 at 21:48
Correct, I am using velocity as speed, basically. – farmdve Dec 12 '12 at 23:17

With your current code if you touch a wall, then if your player's current position differs from their previous position, it negates the velocity. You should probably be checking in which direction the touch occurred, and only allow that direction to be negated if the velocity is in the same direction as the wall.

You still want the player to be able to move away from the wall, so directions opposite to the wall's direction, or perpendicular to the direction of the wall should be allowed.

You will probably want to handle X and Y separately so that when the player enters a corner, you can negate both directions, if they are moving diagonally into the corner.

-
Well, yes, I am doing exactly that. Checking which wall(which corresponds to a direction) was collided to. – farmdve Dec 12 '12 at 19:26
Your current code is only checking positions; it's not checking directions to determine if the velocity in that axis should be negated. It's probably a bit of overkill, but you could do a dot-product of a direction vector(x,y)(where the direction is defined by the wall's position minus the player's postion) with a velocity vector(x,y), and if the result is positive, you'll know you need to negate the velocity. However if it's negative, then you don't negate it. – Paul Dec 12 '12 at 21:36

You aren't differentiating if they are hitting a wall in the x or y axis and just reversing their direction completely. You need to break it down into where they are touching the wall, like you did with what end of the map they moved out of.

-
That is because there is no way to know. As for the end of the map, it was trivial as you had to check if it was < 0 or bigger than the map itself. As for any tile being on any random location in the map, no idea, really. – farmdve Dec 12 '12 at 19:43
Unless you are only moving in one direction at a time, you need to know which side you are hitting on to correctly compensate for collisions. Could you post the touches_wall() code? That would make it more obvious what you need to change. – asbumste Dec 12 '12 at 19:46
This is it pastebin.com/PpJqje1W – farmdve Dec 12 '12 at 19:51
No I can move pretty independently. I can move left or right, or even zig-zag. – farmdve Dec 12 '12 at 20:00