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

Author Topic: The problem with collision  (Read 376 times)

0 Members and 1 Guest are viewing this topic.

darkwolf

  • Newbie
  • *
  • Posts: 1
    • View Profile
    • Email
The problem with collision
« on: November 24, 2024, 05:24:07 pm »
I am trying to implement collision detection from the video by javidx9, "Arbitrary Rectangle Collision Detection & Resolution - Complete," but sometimes, when one object touches another, the first object flies off unexpectedly. This might be related to velocity.y = 0, but I’m not sure about the exact cause. I also discovered that in the DynamicRectVsRect function, when multiplying in_rect_vel.x by fElapsedTime (where in_rect_vel.x == 0), it becomes a very small number instead of zero.
Code:

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


bool RayVsRect(sf::Vector2f ray_origin, sf::Vector2f ray_direction, sf::RectangleShape target, sf::Vector2f& contact_point, sf::Vector2f& contact_normal, float& t_hit_time);
bool DynamicRectVsRect(sf::RectangleShape& in, sf::RectangleShape target, sf::Vector2f in_rect_vel, sf::Vector2f& contact_point, sf::Vector2f& contact_normal, float& contact_time, float fElapsedTime);
sf::Vector2f normalize(sf::Vector2f vector);

int main()
{
        sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
        window.setFramerateLimit(60);

        std::vector<sf::RectangleShape> vRects;

        vRects.push_back(sf::RectangleShape());
        vRects[0].setPosition({10.0f, 10.0f});
        vRects[0].setSize({30.0f, 20.0f});
        sf::Vector2f velocity = {0, 0};

        vRects.push_back(sf::RectangleShape());
        vRects[1].setPosition({ 100.0f, 100.0f });
        vRects[1].setSize({ 80.0f, 50.0f });

        sf::RectangleShape sfml_rect;
        sfml_rect.setPosition({100.0, 100.0});
        sfml_rect.setSize({ 200.0, 200.0 });

        sf::CircleShape circle;
        int circle_rad = 5;
        circle.setFillColor(sf::Color::Red);
        circle.setRadius(circle_rad);

        sf::Vector2f ray_point = {20.0f, 20.0f};
        sf::Vector2f ray_direction;
        sf::Vector2i MousePos;

        sf::Vector2f cp, cn;
        float ct;

        float t;

        sf::Vertex normal[2];

        sf::Clock clock;
        float deltaTime;

        while (window.isOpen())
        {
                MousePos = sf::Mouse::getPosition(window);
                ray_point = sf::Vector2f(vRects[0].getPosition().x+vRects[0].getSize().x/2, vRects[0].getPosition().y + vRects[0].getSize().y / 2);
                ray_direction = sf::Vector2f(MousePos.x - ray_point.x, MousePos.y - ray_point.y);
                deltaTime = clock.restart().asSeconds();
                //std::cout << ray_direction.x << &#39;\t&#39; << ray_direction.y << std::endl;

                if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
                        sf::Vector2f norm_ray_direction = normalize(ray_direction);
                        velocity += sf::Vector2f(norm_ray_direction.x * 100.0f * deltaTime, norm_ray_direction.y * 100.0f * deltaTime);
                }
                //std::cout << velocity.x << &#39;\t&#39; << velocity.y << std::endl;
               
                for (int i = 1; i < vRects.size(); i++) {
                        if (DynamicRectVsRect(vRects[0], vRects[i], velocity, cp, cn, ct, deltaTime)) {
                                velocity += sf::Vector2f(cn.x * std::abs(velocity.x) * (1-ct), cn.y * std::abs(velocity.y) * (1-ct));
                        }
                }
                vRects[0].move(velocity.x * deltaTime, velocity.y * deltaTime);
                std::cout << velocity.x << &#39;\t&#39; << velocity.y << "\t\t" << vRects[0].getPosition().x << &#39;\t&#39; << vRects[0].getPosition().x << std::endl;
                sf::Event event;
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed)
                        {
                                window.close();
                        }
                }

                window.clear(sf::Color::Black);
                for (int i = 0; i < vRects.size(); i++) {
                        window.draw(vRects[i]);
                }
                window.display();
        }

        return 0;

}

bool RayVsRect(sf::Vector2f ray_origin, sf::Vector2f ray_direction, sf::RectangleShape target, sf::Vector2f& contact_point, sf::Vector2f& contact_normal, float& t_hit_near) {

        sf::Vector2f t_near = sf::Vector2f((target.getPosition().x - ray_origin.x) / ray_direction.x,
                                                                           (target.getPosition().y - ray_origin.y) / ray_direction.y);
        sf::Vector2f t_far = sf::Vector2f((target.getPosition().x + target.getSize().x - ray_origin.x) / ray_direction.x,
                                                                          (target.getPosition().y + target.getSize().y - ray_origin.y) / ray_direction.y);

        std::cout << "ray_direction: " << ray_direction.x << &#39;\t&#39; << ray_direction.y << std::endl;
        std::cout << "t_near: " << t_near.x << &#39;\t&#39; << t_near.y << std::endl;
        std::cout << "t_far: " << t_far.x << &#39;\t&#39; << t_far.y << std::endl;

        if (t_near.x > t_far.x) std::swap(t_near.x, t_far.x);
        if (t_near.y > t_far.y) std::swap(t_near.y, t_far.y);

        if (t_near.x > t_far.y || t_near.y > t_far.x) return false;

        //std::cout << "t_near: " << t_near.x << &#39;\t&#39; << t_near.y << std::endl;

        t_hit_near = std::max(t_near.x, t_near.y);
        float t_hit_far = std::min(t_far.x, t_far.y);

        if (t_hit_far < 0) return false;

        contact_point = ray_origin + t_hit_near * ray_direction;

        if (t_near.x > t_near.y)
        {
                if (ray_direction.x < 0)
                {
                        contact_normal = { 1, 0 };
                }
                else
                {
                        contact_normal = { -1, 0 };
                }
        }
        else if (t_near.x < t_near.y)
        {
                if (ray_direction.y < 0)
                {
                        contact_normal = { 0, 1 };
                }
                else
                {
                        contact_normal = { 0, -1 };
                }
        }

        return true;
}


bool DynamicRectVsRect(sf::RectangleShape& in, sf::RectangleShape target, sf::Vector2f in_rect_vel, sf::Vector2f& contact_point, sf::Vector2f& contact_normal, float& contact_time, float fElapsedTime)
{
        if (in_rect_vel.x == 0 && in_rect_vel.y == 0)
                return false;

        sf::RectangleShape expanded_target;
        expanded_target.setPosition(sf::Vector2f(target.getPosition().x - in.getSize().x / 2, target.getPosition().y - in.getSize().y / 2));
        expanded_target.setSize(target.getSize() + in.getSize());

        std::cout << "rect_vel: " << in_rect_vel.x * fElapsedTime << &#39;\t&#39; << in_rect_vel.y * fElapsedTime << std::endl;
        std::cout << "deltaTime: " << fElapsedTime << std::endl;
        if (RayVsRect(sf::Vector2f(in.getPosition().x + in.getSize().x / 2, in.getPosition().y + in.getSize().y / 2), in_rect_vel * fElapsedTime, expanded_target, contact_point, contact_normal, contact_time))
        {
                std::cout << "contact_time: " << contact_time << std::endl;
                if (contact_time <= 1.0f)
                {
                        return true;
                }
        }

        return false;
}

sf::Vector2f normalize(sf::Vector2f vector) {
        float lenght = sqrt(pow(vector.x, 2) + pow(vector.y, 2));
        return sf::Vector2f(vector.x/lenght, vector.y/lenght);
}