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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - darkwolf

Pages: [1]
1
General / 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);
}

Pages: [1]
anything