views:

46

answers:

2

Hi, i'm having some problems with collission in a small 2D game i'm writing. I'm currently working on a function that i want to find if the player character collides with a block, and which side of the block he collided with.

Currently i have something like (psuedo-code):

if(PLAYER_BOX IS WITHIN THE BLOCKS Y_RANGE)
{
    if(PLAYER_BOX_RIGHT_SIDE >= BLOCK_LEFT_SIDE && PLAYER_BOX_RIGHT_SIDE <= BLOCK_RIGHT_SIDE)
    {
        return LEFT;
    }
    else if(PLAYER_LEFT_SIDE <= BLOCK_RIGHT_SIDE && PLAYER_LEFT_SIDE >= BLOCK_LEFT_SIDE)
    {
        return RIGHT;
    }
}
else if(PLAYER_BOX IS WITHIN BLOCK X_RANGE)
{
    if(PLAYER_BOTTOM_SIDE >= BLOCK_TOP_SIDE && PLAYER_BOTTOM_SIDE <= BLOCK_BOTTOM_SIDE)
    {
        return ABOVE;
    }
    else if(PLAYER_TOP_SIDE <= BLOCK_BOTTOM_SIDE && PLAYER_TOP_SIDE >= BLOCK_TOP_SIDE)
    {
        return BELOW;
    }
 }

Do i have some logic error here? Or have i simply wrote something wrong in my code?

ABOVE collision works, but it doesn't recognize sideways collission when it should, and sometimes it does when it should'nt.

The game is a SuperMario clone, so it's a sidescroller 2D platformer.

+2  A: 

I'm guessing the issue is direction.

What you really want to do is to take into account the "player" direction first and then do your checks.

If you don't know what direction the player is moving in you could get a number for false hits depending on how "fast" your sprites are moving.

For example if you have movement directions (up down left right) then your code might look like this:

select movedir
(
   case up:
     //check if hitting bottom of box
     break;
   case down:
     //check if hitting top of box

    etc

}
Hogan
A: 

You might want to consider revising your calculations by using the movement delta.

Something like this (also pseudo):


// assuming player graphics are centered
player_right = player.x + player.width / 2;
player_left = player.x - player.width / 2;

player_top = player.y - player.height / 2;
player_bottom = player.y + player.height / 2;

// assuming block graphics are centered as well
block_right = box.x + box.width / 2;
...

// determine initial orientation
if (player_right  block_right) orientationX = 'right';

if (player_top  block_top) orientationY = 'top';

// calculate movement delta
delta.x = player.x * force.x - player.x;
delta.y = player.y * force.y - player.y;

// define a rect containing where your player WAS before moving, and where he WILL BE after moving
movementRect = new Rect(player_left, player_top, delta.x + player.width / 2, delta.y + player.height / 2);

// make sure you rect is using all positive values
normalize(movementRect);

if (movementRect.contains(new Point(block_top, block_left)) || movementRect.contains(new Point(block_right, block_bottom))) {

    // there was a collision, move the player back to the point of collision
    if (orientationX == 'left') player.x = block_right - player.width / 2;
    else if (orientationX == 'right') player.x = block_left + player.width / 2;

    if (orientationY == 'top') player.y = block_top - player.height / 2;
    else if (orientationY == 'bottom') player.y = block_bottom + player.height / 2;

    // you could also do some calculation here to see exactly how far the movementRect goes past the given block, and then use that to apply restitution (bounce back)

} else {

    // no collision, move the player
    player.x += delta.x;
    player.y += delta.y;

}

This approach is going to give you a lot better results if your player ever moves extremely fast, since you're essentially calculating if the player WILL collide, rather than if they DID collide.

sevenflow