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

Author Topic: Separated Axis Theorm Problem  (Read 1297 times)

0 Members and 1 Guest are viewing this topic.

TheGameDev

  • Newbie
  • *
  • Posts: 7
    • View Profile
Separated Axis Theorm Problem
« 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 :)
« Last Edit: April 05, 2015, 07:21:15 pm by TheGameDev »

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: Separated Axis Theorm Problem
« Reply #1 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.

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.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

TheGameDev

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: Separated Axis Theorm Problem
« Reply #2 on: April 06, 2015, 12:11:52 am »
Sorry :(

PS: The problem was the projection...