Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Whats wrong with my collision detection?  (Read 1754 times)

0 Members and 1 Guest are viewing this topic.

ChayHawk

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Whats wrong with my collision detection?
« on: March 24, 2023, 04:44:29 pm »
So ive been re learning SFML and i really wanted to learn collision, and i understand it far better now, but im still having a few issues, here is my code, what am i doing wrong with my collision? its not working.

//============================================================================
// Name             : SFML Game
// Author           : Chay Hawk
// Version          : 0.0.14
// Version Date     : March 24th 2023 @ 11:27 AM
// Date Created     :
// Lines of Code    : 224
// Description      :
//============================================================================

#include <iostream>
#include <string>
#include <sstream>
#include <SFML/Graphics.hpp>

sf::Text CreateText(const sf::Font& font, int characterSize, const sf::Color& color, float posX, float posY, const std::string& str)
{
    sf::Text text;
    text.setCharacterSize(characterSize);
    text.setFont(font);
    text.setFillColor(color);
    text.setPosition(sf::Vector2f(posX, posY));
    text.setString(str);

    return text;
}

std::unique_ptr<sf::RectangleShape> CreateRectangle(float width, float height, const sf::Color& color, float setXPos, float setYPos)
{
    std::unique_ptr<sf::RectangleShape> rectangle(new sf::RectangleShape);

    rectangle->setSize(sf::Vector2f(width, height));
    rectangle->setFillColor(color);
    rectangle->setPosition(sf::Vector2f(setXPos, setYPos));
    rectangle->setOrigin(sf::Vector2f(rectangle->getSize().x / 2, rectangle->getSize().y / 2));

    return rectangle;
}


int main()
{
    sf::RenderWindow window(sf::VideoMode(1280, 720), "SFML Feature Testing");
    window.setFramerateLimit(60);

    sf::Font Arial;
    Arial.loadFromFile("Resources/Fonts/arial.ttf");

    std::ostringstream oss;
    std::istringstream iss;

    float windowCenterX{ window.getSize().x / 2.0f };
    float windowCenterY{ window.getSize().y / 2.0f };

    sf::Text MouseXText{ CreateText(Arial,  32, sf::Color::White, 0.0f, 0.0f, "Mouse X Position: ") };
    sf::Text MouseXValue{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse X Value: ") };
    sf::Text MouseYText{ CreateText(Arial,  32, sf::Color::White, 0.0f, 0.0f, "Mouse Y Pos: ") };
    sf::Text MouseYValue{ CreateText(Arial, 32, sf::Color::White, 204, 30,    "Mouse Y Value : ") };


    MouseXValue.setPosition(sf::Vector2f(MouseXText.getPosition().x + MouseXText.getGlobalBounds().width, 0.0f));
    MouseYText.setPosition(sf::Vector2f(0, MouseXText.getPosition().y + MouseXText.getGlobalBounds().height + 5));


    //Center Square
    auto square{ CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY) };

    float squareLeft{ };
    float squareTop{ };
    float squareRight{ };
    float squareBottom{ };

    //Squares
    auto cornerSquare_1 { CreateRectangle(35, 35, sf::Color::Blue,  0, 0) };
    auto cornerSquare_2 { CreateRectangle(35, 35, sf::Color::Cyan,  0, 0) };
    auto cornerSquare_3 { CreateRectangle(35, 35, sf::Color::Green, 0, 0) };
    auto cornerSquare_4 { CreateRectangle(35, 35, sf::Color::Red,   0, 0) };


    int playerX{ 150 };
    int playerY{ 150 };

    //Player
    auto player{ CreateRectangle(32, 32, sf::Color::Yellow, playerX, playerY) };

    float playerLeft{ };
    float playerTop{ };
    float playerRight{ };
    float playerBottom{ };

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }

            if (event.type == sf::Event::Resized)
            {
                window.setView(sf::View(sf::FloatRect(0.0f, 0.0f, static_cast<float>(event.size.width), static_cast<float>(event.size.height))));
                square->setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2));
            }
        }

        oss << sf::Mouse::getPosition(window).x;

        MouseXValue.setString(oss.str());

        oss.str("");

        oss << sf::Mouse::getPosition(window).y;

        MouseYValue.setString(oss.str());

        oss.str("");


        /*std::cout << "Player X Position: " << player->getPosition().x << &#39;\n&#39;;
        std::cout << "Player Y Position: " << player->getPosition().y << &#39;\n&#39;;*/


        std::cout << "Player X Left Side:  " << player->getPosition().x - player->getOrigin().x << &#39;\n&#39;;
        std::cout << "Player Y Top:        " << player->getPosition().y - player->getOrigin().y << &#39;\n&#39;;
        std::cout << "Player X Right Side: " << player->getPosition().x + player->getOrigin().x << &#39;\n&#39;;
        std::cout << "Player Y Bottom:     " << player->getPosition().y + player->getOrigin().y << &#39;\n&#39;;

        if (   sf::Mouse::getPosition(window).x >= square->getPosition().x - square->getOrigin().x
            && sf::Mouse::getPosition(window).x <= square->getPosition().x + square->getOrigin().x
            && sf::Mouse::getPosition(window).y >= square->getPosition().y - square->getOrigin().y
            && sf::Mouse::getPosition(window).y <= square->getPosition().y + square->getOrigin().y
            )
        {
            std::cout << "Within white square\n";
        }

        playerLeft = player->getPosition().x - player->getOrigin().x;
        playerTop = player->getPosition().y - player->getOrigin().y;
        playerRight = player->getPosition().x + player->getOrigin().x;
        playerBottom = player->getPosition().y + player->getOrigin().y;

        squareLeft = square->getPosition().x - square->getOrigin().x;
        squareTop = square->getPosition().y - square->getOrigin().y;
        squareRight = square->getPosition().x + square->getOrigin().x;
        squareBottom = square->getPosition().y + square->getOrigin().y;

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
        {
            if (playerTop >= squareBottom)
            {
                player->move(0, -5);
            }
        }

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
        {
            if (playerLeft <= squareRight)
            {
                player->move(-5, 0);
            }
        }

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
        {
            if (playerBottom <= squareTop)
            {
                player->move(0, 5);
            }
        }

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
        {
            if (playerRight >= squareLeft)
            {
                player->move(5, 0);
            }
        }

        //Set cornerSquare to one corner.
        //Bottom Right (Blue)
        cornerSquare_1->setPosition(sf::Vector2f(square->getPosition().x + square->getOrigin().x + cornerSquare_1->getOrigin().x, square->getPosition().y + square->getOrigin().y + cornerSquare_1->getOrigin().y));

        //Top Left (Cyan)
        cornerSquare_2->setPosition(sf::Vector2f(square->getPosition().x - square->getOrigin().x - cornerSquare_2->getOrigin().x, square->getPosition().y - square->getOrigin().y - cornerSquare_2->getOrigin().y));

        //Top Right (Green)
        cornerSquare_3->setPosition(sf::Vector2f(square->getPosition().x + square->getOrigin().x + cornerSquare_3->getOrigin().y, square->getPosition().y - square->getOrigin().y - cornerSquare_3->getOrigin().y));

        //Bottom Left (Red)
        cornerSquare_4->setPosition(sf::Vector2f(square->getPosition().x - square->getOrigin().x - cornerSquare_4->getOrigin().y, square->getPosition().y + square->getOrigin().y + cornerSquare_4->getOrigin().y));
       
        window.clear();
        window.draw(MouseXText);
        window.draw(MouseXValue);
        window.draw(MouseYText);
        window.draw(MouseYValue);
        window.draw(*player);
        window.draw(*square);
        window.draw(*cornerSquare_1);
        window.draw(*cornerSquare_2);
        window.draw(*cornerSquare_3);
        window.draw(*cornerSquare_4);
        window.display();
    }

    return 0;
}
« Last Edit: March 24, 2023, 06:12:51 pm by ChayHawk »

Stauricus

  • Sr. Member
  • ****
  • Posts: 369
    • View Profile
    • A Mafia Graphic Novel
    • Email
Re: Whats wrong with my collision detection?
« Reply #1 on: March 24, 2023, 08:59:37 pm »
what do you mean by "its not working"? what happens?
where do you handle collision? what should be colliding?
Visit my game site (and hopefully help funding it? )
Website | IndieDB

ChayHawk

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: Whats wrong with my collision detection?
« Reply #2 on: March 24, 2023, 09:01:49 pm »
Down near the bottom in the keyboard events area, the player moves but hits collision walls that are nowhere near the square, and when i just comment out all the keys except D, the player will not go past the left side of the square even when its above it. im unsure what exactly im doing wrong but i suspect im not calculating things correctly, i just dont know what.
« Last Edit: March 24, 2023, 09:05:07 pm by ChayHawk »

kojack

  • Sr. Member
  • ****
  • Posts: 343
  • C++/C# game dev teacher.
    • View Profile
Re: Whats wrong with my collision detection?
« Reply #3 on: March 25, 2023, 03:04:15 am »
Let's look at the D key case:
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
        {
            if (playerRight >= squareLeft)
            {
                player->move(5, 0);
            }
        }
The logic here is checking if the playerRight is to the right of the squareLeft. That could mean the player is to the left of the square but overlapping it, or the player is entirely to the right of the square and not overlapping. You don't want to move right if the player is to the left and overlapping.
Also there's no Y axis check in that one. It only considers the X positions, it doesn't check if they overlap on the Y.

To do a full overlap test you can do something like this:
bool overlap = (playerLeft <= squareRight) &&
               (playerRight >= squareLeft) &&
               (playerTop <= squareBottom) &&
               (playerBottom >= squareTop);
 
That will tell if the player and square are currently definitely overlapping.
Although what you really want is to tell if they are going to overlap after a move, not if they currently overlap.

So you could find the desired movement first (don't do the move, just work out what it would be based on the keys), calculate the left, right, top, bottom if the move happened, check if that was an overlap, and don't do the move if overlap is true.

The other way would be to do the move regardless, then correct it afterwards (push the player out of the square). That will make them sit flush a bit better, but it's trickier to implement.

Generally I prefer to just use Box2D and let it deal with everything. :)

ChayHawk

  • Newbie
  • *
  • Posts: 10
    • View Profile
    • Email
Re: Whats wrong with my collision detection?
« Reply #4 on: March 25, 2023, 05:49:14 am »
I tried setting up box2d but it wont work and all the tutorials i find are from like 7 years ago or more :(. I'd love to use it as it seems really cool and makes life easier but i cannot for the life of me get it working despite trying several times over the years and a few hours today. Id rather jump into oncoming traffic than do manual collision detection haha, its probably one of the hardest things ive had to do. Learning C++ wasnt even that hard, but im going to keep trying, i'll get it eventually.
« Last Edit: March 25, 2023, 09:03:10 am by ChayHawk »

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: Whats wrong with my collision detection?
« Reply #5 on: March 25, 2023, 09:36:41 am »
Collision detection is pretty easy if you break it down into smaller actions - it's only really complicated when you start trying to calculate complex physics simulations.

The basics of a collision involve calculating what's called a 'collision manifold'. This is composed of two things: a normal vector indicating the direction of the collision, and a penetration value - ie how much the two objects overlap. With these, resolving the collision usually boils down to moving the colliding object back along the normal vector by the penetration amount.

For AABB - AABB collision and circle-circle collision, finding this manifold is also really easy. I wrote this blog post for SFML specifically, which explains how to do it. Once you have an understanding of these types of collision then it's much easier to extend the technique to other shapes, although in many cases I've found AABB and circle collision is enough  ;D