c++collision-detectionsfmlgravity

After a short time, collision stop working and objectA clip through objectB


Working on a basic joust (a old arcade game) clone, reaching the collision detection, it's seemed to work at first. But i found that when i stay stationary on a platform or even if i move on it, after a bref period (~5sc) i clip trought the platform

I first made some cleaning and test and moving around and test and small refactoring to simplify the detection and test and made it cleaner overall but the detection seemed ok; it work for ~5sc afterall. After that, i thought about the gravity; for it effect the player even on ground and could force the subject to clip. So i maybe a isGrounded variable. So the order of opérations should be: (player start slighty in air) handleCollision say ok no collision -> isGrounded=false player update with effective gravity player fall
then player collide with platorm handleCollision say oh you're on the platform -> isGrounded=true player update should not be affected by gravity

#include "game.h"

Game::Game() : window(sf::VideoMode(windowWidth, windowHeight), "App")
{
    // stuff //

    isGrounded = true;
}
void Game::handleCollision(sf::RectangleShape &A, const sf::RectangleShape &B)
{
    sf::FloatRect BoxA = A.getGlobalBounds();
    sf::FloatRect BoxB = B.getGlobalBounds();

    // Check collision from above
    if (BoxA.intersects(BoxB) && BoxA.top + BoxA.height < BoxB.top + BoxB.height)
    {
        A.setPosition(A.getPosition().x, B.getPosition().y - BoxA.height); // A.getSize().y);
        isGrounded = true;
        std::cout << "Grounded: " << std::endl;
    }
    else
    {
        isGrounded = false;
        std::cout << "In The Air: " << std::endl;
    }
}

void Game::handleCollisions()
{
    handleCollision(player1, platformGround);
}

void Game::update()
{
    float deltaTime = frameTime.asSeconds();

    // Player 1 movement control using keyboard input
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
    {
        player1.move(-playerSpeed * deltaTime, 0);
    }
    else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
    {
        player1.move(playerSpeed * deltaTime, 0);
    }

    // Player 1 flapping control using spacebar
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
    {
        player1Velocity = flapVelocity;
    }

    // Apply gravity only when player is not grounded
    if (!isGrounded)
    {
        player1Velocity += gravity * deltaTime;
    }
    else
    {
        player1Velocity = 0.0f;
    }

    // Update position
    player1.move(0, player1Velocity * deltaTime);

    handleCollisions();
}

That's certainly something stupidly obvious, its (almost) always like that; but thanks in advance for any sort of help.


Solution

  • Ok

    After one week, i kind of found a solution. The thing is, this code work with only two objects and that was the problem since i have 6 collisions check: the flag isGrounded was correctly set to true when touching ground but instantly reset in the next check (because the condition was then false, go to the else part and set isGrounded back to false)

    so after making other minimal example on my side, i came to replacing the original check with:

    if (BoxA.intersects(BoxB) && player1Velocity >= 0.0f)
    {
        // isGrounded = true;
        A.setPosition(A.getPosition().x, BoxB.top - BoxA.height);
        player1Velocity = 0.0f;
        std::cout << "Grounded: " << BoxA.height << std::endl;
    }
    else
    {
        isGrounded = false;
        std::cout << "In The Air: " << std::endl;
    }
    

    Wich now work with the other collisions check even if for now i don't know why, since isGrounded is still set to false and so should activate the gravity effect in the update function.

    But that's another thing, not link to the initial question anymore.