SFML community forums

Help => General => Topic started by: TheGameDev on April 05, 2015, 07:17:32 pm

Title: Separated Axis Theorm Problem
Post by: TheGameDev on April 05, 2015, 07:17:32 pm
Hello,

I'm trying to implement the SAT, and when I move poly2 around it detects the collision even if it don't intersect poly1.

Here's my code:

#include <iostream>
#include <SFML/Graphics.hpp>
#include <vector>
#include "Vector2D.h"

using namespace std;

float getVectorMax(const vector<float>& v)
{
        float max = v[0];

        for (int i = 0; i < v.size(); i++)
        {
                if (v[i] > max)
                        max = v[i];
        }

        return max;
}

float getVectorMin(const vector<float>& v)
{
        float min = v[0];

        for (int i = 0; i < v.size(); i++)
        {
                if (v[i] < min)
                        min = v[i];
        }

        return min;
}


bool SAT(const sf::ConvexShape& one, const sf::ConvexShape& two)
{
        vector<Vector2D> normals;

        //Normals of shape One
        for (int i = 0; i < one.getPointCount(); i++)
        {
                Vector2D side(0,0);
                if (i < one.getPointCount() - 1)
                {
                        side.x = (one.getPoint(i + 1).x + one.getPosition().x) - (one.getPoint(i).x + one.getPosition().x);
                        side.y = (one.getPoint(i + 1).y + one.getPosition().y) - (one.getPoint(i).y + one.getPosition().y);
                }
                else
                {
                        side.x = (one.getPoint(0).x + one.getPosition().x) - (one.getPoint(i).x + one.getPosition().x);
                        side.y = (one.getPoint(0).y + one.getPosition().y) - (one.getPoint(i).y + one.getPosition().y);
                }

                normals.push_back(side.normalVectorOuter());
        }

        //Normals of shape two
        for (int i = 0; i < two.getPointCount(); i++)
        {
                Vector2D side(0, 0);
                if (i < two.getPointCount() - 1)
                {
                        side.x = (two.getPoint(i + 1).x + two.getPosition().x) - (two.getPoint(i).x + two.getPosition().x);
                        side.y = (two.getPoint(i + 1).y + two.getPosition().y) - (two.getPoint(i).y + two.getPosition().y);
                }
                else
                {
                        side.x = (two.getPoint(0).x + two.getPosition().x) - (two.getPoint(i).x + two.getPosition().x);
                        side.y = (two.getPoint(0).y + two.getPosition().y) - (two.getPoint(i).y + two.getPosition().y);
                }

                normals.push_back(side.normalVectorOuter());
        }


        //Project points on normals
        for (int n = 0; n < normals.size(); n++)
        {
                vector<float> projectedPointsOne;
                vector<float> projectedPointsTwo;

                //Get the projected points from shape one
                for (int i = 0; i < one.getPointCount(); i++)
                {
                        projectedPointsOne.push_back(Vector2D((one.getPoint(i).x + one.getPosition().x),
                                                                                (one.getPoint(i).y + one.getPosition().y)).projectedVector(normals[n]).lenght());
                }

                //Get the projected points from shape two
                for (int i = 0; i < two.getPointCount(); i++)
                {
                        projectedPointsTwo.push_back(Vector2D((two.getPoint(i).x + two.getPosition().x),
                                                                                (two.getPoint(i).y + two.getPosition().y)).projectedVector(normals[n]).lenght());
                }

                //Get the min and max of shape one
                float maxOne = getVectorMax(projectedPointsOne);
                float minOne = getVectorMin(projectedPointsOne);

                //Get the min and max of shape two
                float maxTwo = getVectorMax(projectedPointsTwo);
                float minTwo = getVectorMin(projectedPointsTwo);

                //Check if there is at least one gap, if true then -> collision !

                if (maxOne < minTwo || maxTwo < minOne)
                {
                        return false;
                }
        }

        return true;
}


int main(int argc, char** argv)
{
       
        Vector2D v1(1, 1), v2(-1, 1);

        cout << v1.projectedVector(v2) << endl;

        sf::RenderWindow window(sf::VideoMode(500,500,32), "Test");

        sf::ConvexShape poly1;
        poly1.setPointCount(3);
        poly1.setPoint(0, sf::Vector2f(50, -50));
        poly1.setPoint(1, sf::Vector2f(50, 50));
        poly1.setPoint(2, sf::Vector2f(-50, 50));
        poly1.setOutlineThickness(2);
        poly1.setOutlineColor(sf::Color::Red);
        poly1.setPosition(200,200);

        sf::ConvexShape poly2;
        poly2.setPointCount(4);
        poly2.setPoint(0, sf::Vector2f(50, -50));
        poly2.setPoint(1, sf::Vector2f(50, 50));
        poly2.setPoint(2, sf::Vector2f(-50, 50));
        poly2.setPoint(3, sf::Vector2f(-50, -50));
        poly2.setOutlineThickness(2);
        poly2.setOutlineColor(sf::Color::Red);
        poly2.setFillColor(sf::Color::Blue);
        poly2.setPosition(220, 100);

        bool quit = false;
        sf::Event event;

        while (!quit)
        {
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::EventType::Closed)
                        {
                                quit = true;
                        }

                        if (event.type == sf::Event::EventType::KeyPressed && event.key.code == sf::Keyboard::Escape)
                        {
                                quit = true;
                        }
                }

                sf::Vector2i mouse = sf::Mouse::getPosition(window);
                poly2.setPosition(sf::Vector2f(mouse.x, mouse.y));

                if (SAT(poly1, poly2))
                {
                        poly1.setFillColor(sf::Color::Green);
                }
                else{
                        poly1.setFillColor(sf::Color::White);
                }
               
                window.clear(sf::Color::Black);

                window.draw(poly1);
                window.draw(poly2);
                window.display();
        }


        return 0;
}

And My vector class:

#pragma once
#include <iostream>
#include <cmath>

struct Vector2D
{
        float x;
        float y;

        Vector2D(float x, float y)
        {
                this->x = x;
                this->y = y;
        }

        Vector2D operator+(float s)
        {
                return Vector2D(x + s, y + s);
        }

        Vector2D operator+(const Vector2D& v2)
        {
                return Vector2D(x + v2.x, y + v2.y);
        }

        Vector2D operator-(float s)
        {
                return Vector2D(x - s, y - s);
        }

        Vector2D operator-(const Vector2D& v2)
        {
                return Vector2D(x - v2.x, y - v2.y);
        }

        Vector2D operator/(float s)
        {
                return Vector2D(x / s, y / s);
        }

        Vector2D operator*(float s)
        {
                return Vector2D(x * s, y * s);
        }

        float dot(const Vector2D& v2)
        {
                return x * v2.x + y * v2.y;
        }

        float lenght()
        {
                return sqrt((x*x) + (y*y));
        }

        Vector2D normalized()
        {
                return (*this) / this->lenght();
        }

        Vector2D projectedVector(Vector2D& v2)
        {
                return v2 * ((this->dot(v2) / this->lenght()));
        }

        Vector2D normalVectorOuter()
        {
                return Vector2D(-y, x).normalized();
        }

        Vector2D normalVectorInner()
        {
                return Vector2D(y, -x).normalized();
        }
};

std::ostream& operator<<(std::ostream& out, const Vector2D& v)
{
        out << v.x << "," << v.y << std::endl;
        return out;
}

Note that i'm going to refactor that later.

Any idea where I missed something.

Thanks in advance.

Have a nice day :)
Title: Re: Separated Axis Theorm Problem
Post by: Nexus on April 05, 2015, 07:23:40 pm
"There's a mistake in my 300 lines of code, please find it" ::)

This forum does not work like that. Especially not since this is the SFML forum, with questions related to the library and not any game development algorithms. See also this thread (http://en.sfml-dev.org/forums/index.php?topic=5559).

As a programmer, you must learn how to find such problems on your own. Use a debugger, minimize the code, check where the problem occurs.
Title: Re: Separated Axis Theorm Problem
Post by: TheGameDev on April 06, 2015, 12:11:52 am
Sorry :(

PS: The problem was the projection...