Search code examples
c++physicsgame-enginegame-physics

Platforming physics bouncing glitch C++


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;
}
};

Solution

  • 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.