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

Author Topic: The problem with the collision of a circle and squares  (Read 1105 times)

0 Members and 1 Guest are viewing this topic.

Shuvi22

  • Newbie
  • *
  • Posts: 6
    • View Profile
The problem with the collision of a circle and squares
« on: September 04, 2022, 02:58:22 pm »
The problem is in the intersects method. Everything works fine exactly until the circle starts to go into the wall and to the left / up. The circle stops sliding along the wall on the verge of the square and the next square, as if resting on an invisible wall. I tried to change the pass through the objects (if before it started from the first object, now from the last one) and the blocking directions were inverted, that is, the problem is at least partially in this. How can the circle be allowed to slide along the walls regardless of direction?

Code:
#include "math.h"
#include "SFML/Graphics.hpp"

sf::RenderWindow window;
sf::Event event;
sf::View camera;

const int amountOfTile = 32;
sf::RectangleShape tiles[amountOfTile][amountOfTile];
sf::CircleShape player;

void intersects(sf::CircleShape &player, sf::RectangleShape &rect) {
    bool leftIsBlocked = 0;
    bool rightIsBlocked = 0;
    bool topIsBlocked = 0;
    bool bottomIsBlocked = 0;

    float testX = player.getPosition().x;
    float testY = player.getPosition().y;

    //checking which faces the circle intersects
    //originally there were positions of the points of the square, and not a distance from the center. However, the situation is the same in both cases!
    if (player.getPosition().x < rect.getPosition().x - 16) { testX = rect.getPosition().x - 16; leftIsBlocked = 1; } //left
    else if (player.getPosition().x > rect.getPosition().x + 16) { testX = rect.getPosition().x + 16; rightIsBlocked = 1; } //right
    if (player.getPosition().y < rect.getPosition().y - 16) { testY = rect.getPosition().y - 16; topIsBlocked = 1; }  //top
    else if (player.getPosition().y > rect.getPosition().y + 16) { testY = rect.getPosition().y + 16; bottomIsBlocked = 1; } //bottom

    float distX = abs(player.getPosition().x - testX);
    float distY = abs(player.getPosition().y - testY);
    float distance = sqrt((distX * distX) + (distY * distY));

    //if the distance is less than the radius of the circle, then it's time for a collision
    if (distance <= 16) {
        //if any boolean value is active, the distance to the point on the edge of the square is calculated and already it is subtracted / added to the player's position
        //I assume that the error is somewhere here, however, no matter what I change here, it did not help
        if (leftIsBlocked) player.setPosition(player.getPosition().x - abs(16 - distance), player.getPosition().y);
        else if (rightIsBlocked) player.setPosition(player.getPosition().x + abs(16 - distance), player.getPosition().y);
        if (topIsBlocked) player.setPosition(player.getPosition().x, player.getPosition().y - abs(16 - distance));
        else if (bottomIsBlocked) player.setPosition(player.getPosition().x, player.getPosition().y + abs(16 - distance));
    }
}

int main() {
    srand(time(0));
    window.create(sf::VideoMode(1000, 1000), "sfml");
    window.setFramerateLimit(60);

    for (int i = 0; i < amountOfTile; ++i) {
        for (int j = 0; j < amountOfTile; ++j) {
            tiles[i][j].setSize(sf::Vector2f(32, 32));
            tiles[i][j].setOrigin(sf::Vector2f(16, 16));
            tiles[i][j].setFillColor(sf::Color::Red);
            tiles[i][j].setPosition(sf::Vector2f((i + 0) * 32, (j + 0) * 32));
            tiles[i][j].setOutlineThickness(1);
            tiles[i][j].setOutlineColor(sf::Color::Blue);
        }
    }

    for (int i = 0; i < amountOfTile; ++i) {
        for (int j = 0; j < amountOfTile; ++j) {
            if (rand() % 100 > 90) {
                tiles[i][j].setFillColor(sf::Color::Green);
            }
        }
    }

    player.setRadius(16);
    player.setOrigin(sf::Vector2f(16, 16));
    player.setFillColor(sf::Color::White);
    player.setPosition(sf::Vector2f(256, 128));

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

            //resize window
            if (event.type == sf::Event::Resized) {
                sf::Vector2f cameraCenter = camera.getCenter();
                camera.setSize(event.size.width, event.size.height);
                camera.setCenter(cameraCenter);
            }
        }

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) player.move(0, -2.0f);
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) player.move(0, 2.0f);
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) player.move(-2.0f, 0);
        if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) player.move(2.0f, 0);

        //checking all possible collisions (in the future, the nearest ones will be checked)
        for (int i = 0; i < amountOfTile; ++i) {
            for (int j = 0; j < amountOfTile; ++j) {
                if (tiles[i][j].getFillColor() == sf::Color::Green) {
                    intersects(player, tiles[i][j]);
                }
            }
        }
       
        camera.setCenter(player.getPosition());
        window.setView(camera);
        window.clear();

        //in the future I will put tiles in vertex arrays
        for (int i = 0; i < amountOfTile; ++i) {
            for (int j = 0; j < amountOfTile; ++j) {
                window.draw(tiles[i][j]);
            }
        }
        window.draw(player);
        window.display();
    }
    return 0;
}
 

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: The problem with the collision of a circle and squares
« Reply #1 on: September 08, 2022, 01:21:54 pm »
It's unlikely that someone goes through the whole complex-ish code to spot the logic error.
Personally, I haven't really understood the problem description, maybe you can add some images.

I suggest you use a debugger to check the values of your object and/or add some output printing to see the position and size.

You really shouldn't use the window as a global variable. It leads to undefined behavior and crashes.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/