I've been trying to program a tile based game, and I'm stuck at the collision detection.

Here is my code (not the best ^^):

void checkTile(Character *c, int **map)
     int x1,x2,y1,y2;

     /* Character position in the map */
     c->upY     = (c->y)                / TILE_SIZE; // Top left corner
     c->downY   = (c->y + c->h)         / TILE_SIZE; // Bottom left corner
     c->leftX   = (c->x)                / TILE_SIZE; // Top right corner
     c->rightX  = (c->x + c->w)         / TILE_SIZE; // Bottom right corner

     x1         = (c->x + 10)           / TILE_SIZE; // 10px from left side point
     x2         = (c->x + c->w - 10)    / TILE_SIZE; // 10px from right side point
     y1         = (c->y + 10)           / TILE_SIZE; // 10px from top side point
     y2         = (c->y + c->h - 10)    / TILE_SIZE; // 10px from bottom side point

     /* Top */
     if (map[c->upY][x1] > 2 || map[c->upY][x2] > 2)
         c->topCollision = 1;
     else c->topCollision = 0;

     /* Bottom */
     if ((map[c->downY][x1] > 2 || map[c->downY][x2] > 2))
         c->downCollision = 1;
     else c->downCollision = 0;

     /* Left */
     if (map[y1][c->leftX] > 2 || map[y2][c->leftX] > 2)
         c->leftCollision = 1;
     else c->leftCollision = 0;

     /* Right */
     if (map[y1][c->rightX] > 2 || map[y2][c->rightX] > 2)
         c->rightCollision = 1;
     else c->rightCollision = 0;

That calculates 8 collision points

My moving function is like that:

 void movePlayer(Character *c, int **map)
    if ((c->dirX == LEFT && !c->leftCollision) || (c->dirX == RIGHT && !c->rightCollision))
    c->x += c->vx;

    if ((c->dirY == UP && !c->topCollision) || (c->dirY == DOWN && !c->downCollision))
        c->y += c->vy;

    checkPosition(c, map);

and the checkPosition:

void checkPosition(Character *c, int **map)
checkTile(c, map);

if (c->downCollision) {
    if (c->state != JUMPING) {
        c->vy = 0;
        c->y = (c->downY * TILE_SIZE - c->h);

if (c->leftCollision) {
    c->vx = 0;
    c->x = (c->leftX) * TILE_SIZE + TILE_SIZE;

if (c->rightCollision) {
    c->vx = 0;
    c->x = c->rightX * TILE_SIZE - c->w;

This works, but sometimes, when the player is landing on ground, right and left collision points become equal to 1. So it's as if there were collision coming from left or right.

Does anyone know why this is doing this?

  • \$\begingroup\$ As far as I can tell the problem should only be for one frame because checkTile was run before the character was moved up in checkPosition. You could run checkTile again at the end of checkPosition to prevent this. \$\endgroup\$ – aaaaaaaaaaaa Apr 9 '12 at 11:31
  • \$\begingroup\$ Thank you for your answer :) Running the checkTile again isn't a bad idea, I should also run it at the begining of movePlayer. Although, this hasn't fixed the problem. I tried putting a grid on the tileset, and it appears, that the character collides when he's beween 2 tiles. Weird... :S \$\endgroup\$ – Thomas Apr 9 '12 at 13:46
  • \$\begingroup\$ At first I thought you hadn't got any move back in place for when the character falls too far on a single tick, but I see that you have just implemented it using integer division. If the visuals confirm that the character isn't positioned lower than otherwise when this happens that wouldn't seem to be the problem. Can you get out of this lock by jumping? \$\endgroup\$ – aaaaaaaaaaaa Apr 9 '12 at 14:04
  • \$\begingroup\$ I'm not stuck at all, I can jump and move. The thing is that when the Character lands, there's left and right collision (not all the time), putting vx = 0 and replaces the Character either on top of the tile at his right or his left. Thank you for your answers :) \$\endgroup\$ – Thomas Apr 9 '12 at 14:08

Got it, once you get the complete problem description it is elemental.

What happens is that the character end up penetrating the ground by more than 10px after landing due to the speed being greater than 10px per frame, thus causing the lower right and left collision checks to hit the ground. You do move the character up again, but you still decide to stop horizontal movement based on a collision check made before this move. You could just insert another checkTile in the middle of checkPosition.

You should also check before resetting speed to 0 that the character is actually moving in the expected direction, otherwise you can in rare cases get a situation where the character collide with and is halted by an object behind it.

Ain't you supposed to do something about roof collisions in the checkPosition code?

  • \$\begingroup\$ Alright, that makes sense :) Thank you very much, the problem is solved. I'll do it for the top collision, if there is one, Vy will be set to 0. \$\endgroup\$ – Thomas Apr 9 '12 at 14:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.