I don't suppose there are any collision detection superstars in our midst? I've been trying to implement tile-based collision detection in my engine, and like it has in every prior attempt, it's making me its bitch. I feel like I've tried everything and haven't come up with anything to solve several nagging issues. I captured a video below which illustrates one of 'em. Apologies for the crap framerate. Quicktime Player isn't so hot at screen recordings.
http://www.youtube.com/watch?v=Z1gI2hyUjKg
As you can see in the clip, horizontal collisions check out fine on the first few instances where I'm grounded and trying to walk into the solid tiles. It's when I get to the last one that you can see a weird jump/tunneling effect happens when the sprite is moving vertically.
FWIW, this is the code I'm running for the collision detection checks. Can anyone provide me with some help on this issue? I'm totally flustered.
Code:
// Get the player's current position
SDL_Point playerPosition = player.GetPosition();
// Get the player's current speed
SDL_Point playerSpeed = player.GetSpeed();
// Figure out the player's horizontal direction
Direction_t playerDirX;
if (playerSpeed.x < 0)
{
playerDirX = DIRECTION_LEFT;
}
else if (playerSpeed.x > 0)
{
playerDirX = DIRECTION_RIGHT;
}
else
{
playerDirX = DIRECTION_NONE;
}
// Get the player's horizontal edge based on their direction; ignore anything but left and right for now
int playerEdgeX = 0;
switch (playerDirX)
{
case DIRECTION_LEFT:
playerEdgeX = playerPosition.x;
break;
case DIRECTION_RIGHT:
playerEdgeX = playerPosition.x + player.GetSprite()->GetWidth();
break;
default:
break;
}
// Don't bother with the next steps if the player isn't moving horizontally
if (playerDirX != DIRECTION_NONE)
{
// Get the player's vertical edges
int playerEdgeTopY = playerPosition.y;
int playerEdgeBottomY = playerPosition.y + player.GetSprite()->GetHeight();
std::vector<Tilemap *>::const_iterator tm;
for (tm=tilemaps.begin(); tm != tilemaps.end(); ++tm)
{
// Get the size of tiles
int tileSize = (*tm)->GetTilesheet()->GetTileSize();
// Figure out which rows the player is currently intersecting with
int topRow = (int)playerEdgeTopY / tileSize;
int bottomRow = (int)playerEdgeBottomY / tileSize;
// Figure out which column the player is currently intersecting with
int inCol = playerEdgeX / tileSize;
// Iterate over the rows...
for (int tileRow=topRow; tileRow<bottomRow; ++tileRow)
{
// Get the Tile
Tile *tile = (*tm)->GetTilesheet()->GetTileAtIndex((*tm)->GetTileKeyAtIntersection(tileRow, inCol));
// Check if it's solid
if (tile->GetType() == TILETYPE_GROUND)
{
int tileEdgeX = 0;
//int overlapX = 0;
int newPlayerX = playerPosition.x;
switch (playerDirX)
{
case DIRECTION_LEFT:
tileEdgeX = ((inCol * tileSize) + tileSize);
newPlayerX = tileEdgeX;
break;
case DIRECTION_RIGHT:
tileEdgeX = (inCol * tileSize);
newPlayerX = (tileEdgeX - player.GetSprite()->GetWidth());
break;
default:
break;
}
// Adjust the player's position to the edge of the solid tile
player.SetX(newPlayerX);
// Stop further movement
player.SetSpeedX(0);
// Update the player's collider w/ the new coords
player.GetSprite()->GetCollider()->UpdateRect(newPlayerX, playerPosition.y, player.GetSprite()->GetWidth(), player.GetSprite()->GetHeight());
}
}
}
}