I'm working out the basics oof the Seperating Axis Theorem, and using this code I found http://en.sfml-dev.org/forums/index.php?topic=12063.0 (http://en.sfml-dev.org/forums/index.php?topic=12063.0) I was able to create this little program that works fine, in the respect that it simply returns whether the two objects collide. My question is, what do I do next to set the two objects apart from each other, but in the shortest distance possible. Most tutorials say "project one shape onto the axis of shortest distance between the two shapes" but I'm not sure how to do that code-wise. Here is the working program// SFML Test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "SFML\Graphics.hpp"
#include <iostream>
class Object : public sf::Drawable, public sf::Transformable{
public:
Object() : shape( sf::TrianglesStrip, 6 ), verts( 4 ){
//so this would create a sword (kind of) but other objects would instantiate these points as they see fit
shape[0].position = sf::Vector2f(80, 100);
shape[1].position = sf::Vector2f(80, 20);
shape[2].position = sf::Vector2f(100, 100);
shape[3].position = sf::Vector2f(100, 20);
shape[4].position = sf::Vector2f(90, 10);
shape[5].position = sf::Vector2f(80, 20);
}
sf::VertexArray& getShape()
{return shape;}
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
{
states.transform *= getTransform();
target.draw( shape, states);
for( int i = 0; i < verts.size(); i++ )
{
target.draw( verts[i], states);
}
}
//each 2d shape will be made of various points, whether it is a simple square or a shape like a sword
sf::VertexArray shape;
//I think this is just for decoration, nothing required
std::vector<sf::CircleShape> verts;
};
sf::Vector2f normalize( sf::Vector2f& input )
{
if( sqrt(input.x*input.x + input.y*input.y) == 0 )
{
input.x = 1;
return input;
}
float length = sqrt(input.x*input.x + input.y*input.y);
input.x /= length;
input.y /= length;
return input;
}
sf::Vector2f getNormalAxis( sf::VertexArray& shape, int index )
{
sf::Vector2f vector1 = shape[index].position;
sf::Vector2f vector2;
if( index >= shape.getVertexCount() - 1 )
vector2 = shape[0].position;
else
vector2 = shape[index+1].position;
sf::Vector2f normalAxis( -(vector2.y - vector1.y), vector2.x - vector1.x );
normalAxis = normalize( normalAxis );
return normalAxis;
}
float dotProduct( sf::Vector2f& vector1, sf::Vector2f& vector2 )
{
return vector1.x*vector2.x + vector1.y*vector2.y;
}
bool sat( Object& shape1, Object& shape2 )
{
sf::Vector2f vectorOffset( shape1.getPosition().x - shape2.getPosition().x, shape1.getPosition().y - shape2.getPosition().y );
for( int i = 0; i < shape1.getShape().getVertexCount(); i++ )
{
sf::Vector2f axis = getNormalAxis( shape1.getShape(), i );
float min1 = dotProduct( axis, shape1.getShape()[0].position );
float max1 = min1;
for( int j = 1; j < shape1.getShape().getVertexCount(); j++ )
{
float testNum = dotProduct( axis, shape1.getShape()[j].position );
if( testNum < min1 )
min1 = testNum;
if( testNum > max1 )
max1 = testNum;
}
float min2 = dotProduct( axis, shape2.getShape()[0].position );
float max2 = min2;
for( int j = 1; j < shape2.getShape().getVertexCount(); j++ )
{
float testNum = dotProduct( axis, shape2.getShape()[j].position );
if( testNum < min2 )
min2 = testNum;
if( testNum > max2 )
max2 = testNum;
}
float offset = dotProduct( axis, vectorOffset );
min1 += offset;
max1 += offset;
float test1 = min1 - max2;
float test2 = min2 - max1;
if( test1 > 0 || test2 > 0 )
return 0;
}
return 1;
}
int _tmain(int argc, _TCHAR* argv[]){
sf::RenderWindow window(sf::VideoMode(500, 500, 32), "Test");
Object object;
Object objectTwo;
objectTwo.getShape().resize(4);
while(window.isOpen()){
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)){
window.close();
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
for(int i = 0; i < objectTwo.getShape().getVertexCount(); i++){
objectTwo.getShape()[i].position.x += .05;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
for(int i = 0; i < objectTwo.getShape().getVertexCount(); i++){
objectTwo.getShape()[i].position.x -= .05;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
for(int i = 0; i < objectTwo.getShape().getVertexCount(); i++){
objectTwo.getShape()[i].position.y += .05;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
for(int i = 0; i < objectTwo.getShape().getVertexCount(); i++){
objectTwo.getShape()[i].position.y -= .05;
}
}
/*you may want to change this if you don't like your console being flooded with outputs*/
std::cout << sat(object, objectTwo);
window.clear();
window.draw(objectTwo);
window.draw(object);
window.display();
}
return 0;
}
So if the moving square runs into the complex shape, how would I reset the square just outside of the other shape? References to this code would be nice, but a link to a good tutorial on this would work just as well, thanks.
When calculating the overlap of the shapes, the code in the tutorial just says double overlap = // really large number;
What the heck does "really large number" mean? How did you end up calculating the overlap of the shapes?