[SOLVED] 2d platformer collision
Posted: Mon Jan 30, 2012 11:25 pm
So I'm going to go ahead and ask a question that many have asked before, not because I haven't read the relevant posts, but because I can't seem to square away an implementation that works for me. I'm going to assume this is a lack of experience and knowledge on my part, however, maybe some of you can steer me in a useful direction. I've got a simple tile rendering system set up that reads from a file and stores my tiles into a std::vector. I have implemented some crude gravity that constantly pulls the player downward. I am having some serious issues with resolving the collisions. What I am trying to do is to calculate the amount of overlap between the bounding box of the player and the bounding box of the tile, and "pop" the player out of the tile by the amount of overlap. Here is the code I'm working with:
So this is my update function for entities. PosValid basically looks at the tiles the player is occupying and when one of them is impassable, it passes a pointer to it to a function called HandleTileCollisions. Here are the relevant functions:
The HandleTileCollisions function is an algorithm I got from one of falco's posts that delt with this very same issue. When I actually run this code, it's beyond broken. Is there something obvious that I'm missing?
Code: Select all
void CEntity::OnUpdate()
{
X += SpeedX * CFPS::FPSControl.GetSpeedFactor();
Y += SpeedY * CFPS::FPSControl.GetSpeedFactor();
PosValid(X, Y);
if (SpeedY < 10)
{
SpeedY += Gravity * CFPS::FPSControl.GetSpeedFactor(); //apply gravity
}
if(Y > Floor)
{
Jumping = false;
Y = Floor;
}
if(X > 640 - 32)
{
X = 608;
SpeedX = 0.0f;
}
if (X < 0)
{
X = 0;
SpeedX = 0.0f;
}
}
Code: Select all
bool CEntity::PosValid(int x, int y)
{
int StartX = x / TILE_SIZE;
int StartY = y /TILE_SIZE;
int EndX = (x + Width) / TILE_SIZE;
int EndY = (y + Height) / TILE_SIZE;
for(int iY = StartY;iY <= EndY;iY++)
{
for(int iX = StartX;iX <= EndX;iX++)
{
CTile* Tile = CMap::MapControl.GetTilePtr(iX * TILE_SIZE, iY * TILE_SIZE);
if(Tile->TypeID == 2)
{
SDL_Rect tileRect;
tileRect.x = iX * TILE_SIZE;
tileRect.y = iY * TILE_SIZE;
tileRect.w = TILE_SIZE;
tileRect.h = TILE_SIZE;
HandleTileCollision(&tileRect);
}
}
}
return true;
}
void CEntity::HandleTileCollision(SDL_Rect* Tile)
{
SDL_Rect player = GetRect();
//set x and y coordinates to the center
float pX = player.x + 0.5 * player.w;
float pY = player.y + 0.5 * player.h;
float tX = Tile->x + 0.5 * Tile->w;
float tY = Tile->y + 0.5 * Tile->h;
//determine overlap for each axis
float xDist = fabs(pX - tX);
float yDist = fabs(pY - tY);
//minimal amount of distance that the two can be apart and not collide
float xMinDist = Tile->w + player.w;
float yMinDist = Tile->h + player.h;
if(xDist >= xMinDist || yDist >= yMinDist) return; //neither axis is colliding
float xOverlap = xDist - xMinDist;
float yOverlap = yDist - yMinDist;
if(xOverlap < yOverlap) X += xOverlap;
else Y += yOverlap;
}