I am implementing some very basic platforming physics in C++ for a simple tile-based platformer. I am following the algorithm here (https://gamedev.stackexchange.com/questions/18302/2d-platformer-collisions) as exactly as I can yet I am still getting a weird glitch where the player bounces on a tile. I'm not exactly sure what is going on. The code is in C++ using SDL
void Player::update(vector< vector<Tile> > map) {
vector<Tile> collidingTiles;
x += xVel;
y += yVel;
boundingBox = Rect(x,y,16,16);
for(int iy=0;iy<MAPH;iy++) {
for(int ix=0;ix<MAPW;ix++) {
if (map[ix][iy].solid == true) {
if (boundingBox.collide(map[ix][iy].boundingBox)) {
collidingTiles.push_back(map[ix][iy]); // store all colliding tiles, will be used later
Rect intersectingRect = map[ix][iy].boundingBox; // copy the intersecting rect
float xOffset = x-intersectingRect.x; // calculate x-axis offset
float yOffset = y-intersectingRect.y; //calculate y-axis offset
if (abs(xOffset) < abs(yOffset)) {
x += xOffset;
}
else if (abs(xOffset) > abs(yOffset)) {
y += yOffset;
}
boundingBox = Rect(x,y,16,16); // reset bounding box
yVel = 0;
}
}
}
}
if (collidingTiles.size() == 0) {
yVel += gravity;
}
};
if (abs(xOffset) < abs(yOffset)) {
x += xOffset;
}
else if (abs(xOffset) > abs(yOffset)) {
y += yOffset;
}
yVel = 0;
In this code, if abs(xOffset) == abs(yOffset)
, nothing happens, meaning that the player can enter a solid tile diagonally. Removing the second test should remove the issue and modify y
if the algorithm has to make a choice:
Also, I'm wondering if you really want to reset the vertical velocity if a horizontal collision occurs. This also implies that gravity should still apply if the collision was horizontal (otherwise the walls and ceiling would be sticky).
int gravityApplies = true;//fix 2a
...
if (abs(xOffset) < abs(yOffset)) {
x += xOffset;
xVel = 0; //fix 2
}
else { //fix 1
y += yOffset;
yVel = 0; //fix 2
if( yOfsset < 0 ){ // fix 2a
gravityApplies = false;
}
}
...
if (gravityApplies) { //fix 2a
yVel += gravity;
}
If you want elastic collisions, use yVel = -yVel
instead of yVel = 0
(and similar for the other direction). You can even do yVel = yVel * rest
where rest
ranges from -1
to 0
(-0.8
is a good choice) to get semi-elastic collisions.