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