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 - wh1t3crayon

Pages: [1] 2 3 ... 7
1
Graphics / Re: Why is there a slight gap between my sf::ConvexShapes?
« on: December 01, 2015, 03:47:42 am »
Well this is a little embarrassing. In Platform's constructor,
Platform(int posX, int posY, int tileSize){
    //shape.setPosition(posX * tileSize, posY * tileSize);
                shape.setPointCount(4);
                shape.setPoint(0, sf::Vector2f(posX + tileSize, posY));
                shape.setPoint(1, sf::Vector2f(posX, posY));
                shape.setPoint(2, sf::Vector2f(posX, posY + tileSize));
                shape.setPoint(3, sf::Vector2f(posX + tileSize, posY + tileSize));
                shape.setFillColor(sf::Color::White);
        }
The setPosition function was messing with the shapes' positions (yes that's redundant). I commented that out and the gap went away.

2
Graphics / Re: Why is there a slight gap between my sf::ConvexShapes?
« on: December 01, 2015, 03:27:43 am »
Quote
What is SCREEN_WIDTH and SCREEN_HEIGHT?
Ah, forgot about those. They're just constant integers, available to all classes, set at 1280 and 720 respectively.

3
Graphics / Re: Why is there a slight gap between my sf::ConvexShapes?
« on: November 30, 2015, 07:42:17 pm »
Quote
It looks like your positions might be non-integer so try rounding them to see if that fixes your problem.
The debugger showed that they are integer positions; nevertheless, rounding them, ceiling, or flooring them did not change the nature of the gaps a bit.
Quote
Are you using a view?
I am using a view. I'll show how I'm implementing it:
class WorldObject{
//...
    sf::Drawable &GetDrawable(){
        return shape;
    }
};

class Level{
//...
public:
void SetActive(std::vector<WorldObject*> &permObjects, int levelNumber, int tileSize){
    //other code not relevant to the objects vector

                //parse given level file for all relevant startup info
                std::ifstream fin;
                std::string str("levels/level" + std::to_string(levelNumber) + ".txt");
                fin.open(str);
                int yCounter = 0; //incr whenever file reads /n
                                std::string line;
                                while(std::getline(fin, line)){
                                        for(int xCounter = 0; xCounter < line.length(); xCounter++){
                                                if(line[xCounter] == 'w'){
                                                        AddWall(xCounter, yCounter, tileSize);
                                                }
                                        }
                                        yCounter++;
                                }
                fin.close();
        }

std::vector<WorldObject*> &GetLevelObjects(){
        return objects;
}
private:
std::vector<WorldObject*> objects;
};

class Board{
public:
//...
void MoveCameraCenter(float offsetX, float offsetY){
        cameraCenter += sf::Vector2f(offsetX, offsetY);
}

std::vector<WorldObject*> &GetObjects(){
        return activeLevel.GetLevelObjects();
}

sf::View GetCamera(){
        sf::View camera;
        camera.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
        camera.setCenter(cameraCenter);
        return camera;
}
private:
        sf::Vector2f cameraCenter;
};

class Engine{
private:
        Board board;

    //the view isn't called for until Render()
    void Engine::Render(){
        window.setView(board.GetCamera());

        window.clear();
        for(unsigned i = 0; i < board.GetObjects().size(); i++){
            window.draw(board.GetObjects()[i]->GetDrawable());
        }
        window.display();
    }
};
 

That should be all the relevant code, but if you need anything else let me know

4
Graphics / Re: Why is there a slight gap between my sf::ConvexShapes?
« on: November 30, 2015, 02:20:00 pm »
Well, thanks for the coding tips, it all is slightly more optimized now. But the gaps between the shapes remain. And it has nothing to do with the file that I'm reading from, because even if I create side by side shapes by hardcoding in their positions, the gap is still there. Any other suggestions?

AddWall(0, 0, tileSize);
AddWall(1, 0, tileSize);
(two side by side shapes, but there is still a 1 pixel wide gap)

5
Graphics / Why is there a slight gap between my sf::ConvexShapes?
« on: November 24, 2015, 10:04:06 pm »
When creating a row of sf::ConvexShapes from data in a .txt file, there is a slight gap between each shape. If I create each shape with the same data inside the code itself, then there is no gap formed.
std::ifstream fin;
std::string str("levels/level" + std::to_string(levelNumber) + ".txt");
fin.open(str);
int yCounter = 0; //incr whenever file reads /n
if(fin.good()){
        while(!fin.eof()){
                std::string line;
                //this happens once per line, so whenever the while statement breaks, that means incr yCounter
                while(std::getline(fin, line)){
                        int xCounter = 0; //incr for each char, reset per line
                        for(int i = 0; i < line.length(); i++){
                                if(line[i] == 'w'){
                                        AddWall(xCounter, yCounter, tileSize);
                                }
                                xCounter++;
                        }
                        yCounter++;
                }
        }
}

void AddWall(int posX, int posY, int tileSize){
        objects.push_back(new Platform(posX, posY, tileSize));
}

Platform::Platform(int posX, int posY, int tileSize){
        shape.setPointCount(4);
        shape.setPoint(0, sf::Vector2f(posX, posY));
        shape.setPoint(1, sf::Vector2f(posX, posY + tileSize));
        shape.setPoint(2, sf::Vector2f(posX + tileSize, posY + tileSize));
        shape.setPoint(3, sf::Vector2f(posX + tileSize, posY));
        shape.setFillColor(sf::Color::White);
        shape.setPosition(posX * tileSize, posY * tileSize);
}

A screenshot of the gap is included. I know I can just add outlines to the shapes to solve this, but why is the problem happening in the first place?

6
Graphics / Re: How to have a pointer to sf::Drawable in a base class?
« on: September 25, 2015, 03:10:08 am »
I'm sorry I must have mispoken. As you can see in the code, sf::Drawable isn't the base class itself. WorldObject is the base class, and WorldObject owns a pointer to sf::Drawable. Accessing this pointer from a container of WorldObjects throws the runtime error.

7
Graphics / How to have a pointer to sf::Drawable in a base class?
« on: September 25, 2015, 02:14:07 am »
When running the code below I am getting the following runtime error:
Quote
Unhandled exception at 0x5E87CC6E (sfml-graphics-d-2.dll) in Project for SFML Web Problems.exe: 0xC0000005: Access violation reading location 0xCCCCCCD0.

// Project for SFML Web Problems.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "SFML\Graphics.hpp"
#include <deque>
#include <memory>

class WorldObject{
public:
        WorldObject(){ drawable = nullptr; }
        virtual ~WorldObject(){}

        sf::Drawable &GetDrawable(){
                return *drawable;
        }
protected:
        //accessing this pointer is invalid
        sf::Drawable *drawable;
};

class Entity : public WorldObject{
public:
        Entity(){
                sprite.setPosition(20, 20);
                sprite.setFillColor(sf::Color::White);
                sprite.setSize(sf::Vector2f(50, 50));

                drawable = &sprite;
        }
        virtual ~Entity(){}
private:
        sf::RectangleShape sprite;
};

class Holder{
public:
        Holder(){
                entities.push_back(Entity());
                objects.push_back(&entities[0]);       
        }
        ~Holder(){}

        std::deque<WorldObject*> &GetObjects(){
                return objects;
        }
        std::deque<Entity> &GetEntities(){
                return entities;
        }
private:
        std::deque<WorldObject*> objects;
        std::deque<Entity> entities;
};

int _tmain(int argc, _TCHAR* argv[])
{
        sf::RenderWindow window(sf::VideoMode(500, 500, 32), "Test");
        sf::Event ev;

        Holder holder;

        while(window.isOpen()){
                while(window.pollEvent(ev)){
                        if(ev.type == sf::Event::Closed){
                                window.close();
                        }
                }
                window.clear();
                for(unsigned int i= 0; i < holder.GetObjects().size(); i++){
                        //accessing sf::Drawable* throws error
                        window.draw(holder.GetObjects()[i]->GetDrawable());
                }
                window.display();
        }

        return 0;
}

 

My question is pretty straightforward. How do I make a pointer to sf::Drawable in a Base class so that in a Base container I can draw that drawable, be it a sf::Sprite, sf::RectangleShape, etc.?

8
Thank you so much, it's working now. Don't take this as ingratitude because I'm quite grateful for the help, but why does @Lektor get the exact line of code he needs while I just get links and angry emoticons?

9
Thanks for pointing that out. What is a reasonable workaround for this? How would I get the global coordinates of the shape's points?

10
Okay so I discovered something different entirely. Whenever I move() a ConvexShape, the values that GetPoint() returns stay the same.
sf::ConvexShape shape;
shape.setPointCount(1);
shape.setPoint(0, sf::Vector2f(20, 20));

sf::VertexArray otherShape;
otherShape.setPrimitiveType(sf::PrimitiveType::Quads);
otherShape.append(sf::Vertex(sf::Vector2f(20, 20)));
otherShape.append(sf::Vertex(sf::Vector2f(20, 20)));
otherShape.append(sf::Vertex(sf::Vector2f(20, 20)));
otherShape.append(sf::Vertex(sf::Vector2f(20, 20)));

std::cout << shape.getPoint(0).y << " "; //ALWAYS 20
shape.move(0, 50);
std::cout << shape.getPoint(0).y << "\n"; //ALWAYS 20, even though the shape was explicitly moved

std::cout << otherShape[0].position.y << " "; //20...
for(int i = 0; i < otherShape.getVertexCount(); i++){
        otherShape[i].position.y += 50;
}
std::cout << otherShape[0].position.y; //then 70, as I would expect
 
This really bugs me, no pun intended. Why don't the position values of a ConvexShape's points update when the shape is moved?

11
The I set two vertex array primitives in the initial part of the code,
object.GetOutline().setPrimitiveType(sf::PrimitiveType::Triangles);
    //append points

    objectTwo.GetOutline().setPrimitiveType(sf::PrimitiveType::Quads);
    //append points
 

Even if I set them both to Quads, the ConvexShape code is still failing. The issue is in the Projection constructor(s). In the ctor that takes a ConvexShape, when I debug to look at the variables min and max, the min for some reason wants to be -0 sometimes. But in the exact same ctor that takes a vertex array, the min is set to where it should be (around 160.f if you collide the shapes by just holding the down arrow).

Edit: particularly, the second point in the convex shape, when used in the DotProduct function in Projection's ctor, results in -0 everytime. Actually, the first point's y position of the ConvexShape (objectTwo) is always -0. I'll show where I mean in the code
Projection(sf::Vector2f &axis, sf::ConvexShape &shape){
                min = DotProduct(axis, shape.getPoint(0)); //when Projection is being created from objectTwo
//(the moving object), this line always returns -0, because objectTwo's y coord is always -0. Why?
                max = min;
/*so this loop is called for every point the convex shape has, and on the second point it screws up:
on the first point, min == -180, which is what its supposed to be. However, the second time, min == -0.
 Moreover, when passed a vertex array instead, min == -160.005f, for the second point which is what it's supposed to be.*/


                for(int i = 1; i < shape.getPointCount(); i++){
                        float proj = DotProduct(axis, shape.getPoint(i));
                        if(proj < min){
                                min = proj;
                        }
                        else if(proj > max){
                                max = proj;
                        }
                }
        }

12
I was able to narrow it down a lot, but I'm still confused. When creating my Projection objects, I can use a ConvexShape for the stationary object, but for the moveable object I have to send the vertex array. Here is what I mean
class WorldObject{
public:
        WorldObject(){}
        ~WorldObject(){}

        sf::ConvexShape &GetShape(){ return shape; }
        sf::VertexArray &GetOutline(){ return outline; }
private:
        //this is the only major change, a vertex array to a convex shape
        sf::ConvexShape shape;
        sf::VertexArray outline;
};

class Projection{
public:
        Projection(sf::Vector2f &axis, sf::ConvexShape &shape){
                min = DotProduct(axis, shape.getPoint(0));
                max = min;

                for(int i = 1; i < shape.getPointCount(); i++){
                        float proj = DotProduct(axis, shape.getPoint(i));
                        if(proj < min){
                                min = proj;
                        }
                        else if(proj > max){
                                max = proj;
                        }
                }
                //std::cout << min << " " << max << "\n";
        }
        Projection(sf::Vector2f &axis, sf::VertexArray &shape){
                min = DotProduct(axis, shape[0].position);
                max = min;

                for(int i = 1; i < shape.getVertexCount(); i++){
                        float proj = DotProduct(axis, shape[i].position);
                        if(proj < min){
                                min = proj;
                        }
                        else if(proj > max){
                                max = proj;
                        }
                }
                //std::cout << min << " " << max << "\n";
        }
//...

};

//later in the collision checking code
Projection projectionOne(axesOne[i], object.GetShape());
//found it. why does object two need to send its outline?
Projection projectionTwo(axesOne[i], objectTwo.GetOutline());

So why is there a difference here between using a ConvexShape and VertexArray?

13
General / Issue with using a ConvexShape's points like a VertexArray
« on: April 15, 2015, 06:23:26 am »
A while back I made a crude implementation of the Separating Axis Theorem, although I used the sf::VertexArray to represent an object. When adapting this to an actual project, I found that my objects on the screen were better off as sf::ConvexShapes, not VertexArrays. So I thought the adaptation for the SAT code would be straightforward, but it's not. The new SAT code using ConvexShapes always returns the overlaps of the shapes as zero. So somewhere in these two similar blocks of code, there is a bug that I seem to have missed when turning all the VertexArray code into ConvexShape code. Maybe all I need is a second pair of eyes, or maybe there's something between these two sf classes that I don't know about, but I'd appreciate it if somebody took the time to compare the two different code blocks. I'll post the before and after code.
The working SAT code, sf::VertexArray friendly:
// SFML Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "SFML\Graphics.hpp"

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 vectorOne = shape[index].position;
    sf::Vector2f vectorTwo;
    if(index >= shape.getVertexCount() - 1)
        vectorTwo = shape[0].position;
    else
        vectorTwo = shape[index+1].position;

    sf::Vector2f normalAxis(-(vectorTwo.y - vectorOne.y), vectorTwo.x - vectorOne.x);
    normalAxis = Normalize(normalAxis);
    return normalAxis;
}

float DotProduct(sf::Vector2f &vectorOne, sf::Vector2f &vectorTwo){
    return vectorOne.x * vectorTwo.x + vectorOne.y * vectorTwo.y;
}

class WorldObject{
public:
        WorldObject(){}
        ~WorldObject(){}

        sf::VertexArray &GetOutline(){ return outline; }
private:
        sf::VertexArray outline;
};

class Projection{
public:
        Projection(sf::Vector2f &axis, sf::VertexArray &vertices){
                min = DotProduct(axis, vertices[0].position);
                max = min;

                for(int i = 1; i < vertices.getVertexCount(); i++){
                        float proj = DotProduct(axis, vertices[i].position);
                        if(proj < min){
                                min = proj;
                        }
                        else if(proj > max){
                                max = proj;
                        }
                }
        }
        ~Projection(){}

        float GetMin(){ return min; }
        float GetMax(){ return max; }

        float GetOverlap(Projection &projection){
                if(projection.GetMin() <= max && max <= projection.GetMax()){
                        return max - projection.GetMin();
                }
                else if(min <= projection.GetMax() && projection.GetMax() <= max){
                        return projection.GetMax() - min;
                }
                else{
                        return 0;
                }
        }
private:
        float min, max;
};

int _tmain(int argc, _TCHAR* argv[]){
        sf::RenderWindow window(sf::VideoMode(500, 500, 32), "Test");

        WorldObject object;
        WorldObject objectTwo;

        object.GetOutline().setPrimitiveType(sf::PrimitiveType::Triangles);
        object.GetOutline().append(sf::Vertex(sf::Vector2f(200, 180)));
        object.GetOutline().append(sf::Vertex(sf::Vector2f(10, 180)));
        object.GetOutline().append(sf::Vertex(sf::Vector2f(10, 240)));
        //object.GetOutline().append(sf::Vertex(sf::Vector2f(200, 240)));

        objectTwo.GetOutline().setPrimitiveType(sf::PrimitiveType::Quads);
        objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(20 + 80, 0)));
        objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(0 + 80, 0)));
        objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(0 + 80, 20)));
        objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(20 + 80, 20)));

        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.GetOutline().getVertexCount(); i++){
                                objectTwo.GetOutline()[i].position.x += .05;
                        }
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
                        for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
                                objectTwo.GetOutline()[i].position.x -= .05;
                        }
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
                        for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
                                objectTwo.GetOutline()[i].position.y += .05;
                        }
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
                        for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
                                objectTwo.GetOutline()[i].position.y -= .05;
                        }
                }

                if(sf::FloatRect(object.GetOutline().getBounds()).intersects(sf::FloatRect(objectTwo.GetOutline().getBounds()))){
                        std::vector<sf::Vector2f> axesOne;
                        std::vector<sf::Vector2f> axesTwo;
                        //for both shapes, get their axes
                        for(int i = 0; i < object.GetOutline().getVertexCount(); i++){
                                axesOne.push_back(GetNormalAxis(object.GetOutline(), i));
                        }
                        for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
                                axesTwo.push_back(GetNormalAxis(objectTwo.GetOutline(), i));
                        }

                        //for both sets of axes
                        //project
                        float overlap = 50000000000;
                        sf::Vector2f smallestAxis;
               
                        for(int i = 0; i < axesOne.size(); i++){
                                Projection projectionOne(axesOne[i], object.GetOutline());
                                Projection projectionTwo(axesOne[i], objectTwo.GetOutline());

                                float o = projectionOne.GetOverlap(projectionTwo);
                                if(o == 0.f){
                                        //no overlap
                                }
                                if(o < overlap){
                                        overlap = o;
                                        smallestAxis = axesOne[i];
                                }
                        }

                        for(int i = 0; i < axesTwo.size(); i++){
                                Projection projectionOne(axesTwo[i], object.GetOutline());
                                Projection projectionTwo(axesTwo[i], objectTwo.GetOutline());

                                //but here, GetOverlap() actually returns a non zero number
                                float o = projectionOne.GetOverlap(projectionTwo);
                                if(o == 0.f){
                                        //no overlap
                                }
                                if(o < overlap){
                                        overlap = o;
                                        smallestAxis = axesTwo[i];
                                }
                        }

                        sf::Vector2f distance, aPos, bPos;
                        aPos = sf::Vector2f(object.GetOutline().getBounds().left + object.GetOutline().getBounds().width / 2, object.GetOutline().getBounds().top + object.GetOutline().getBounds().height / 2);
                        bPos = sf::Vector2f(objectTwo.GetOutline().getBounds().left + objectTwo.GetOutline().getBounds().width / 2, objectTwo.GetOutline().getBounds().top + objectTwo.GetOutline().getBounds().height / 2);
                        distance = aPos - bPos;

                        if(DotProduct(distance, smallestAxis) < 0.0f){
                                smallestAxis = -smallestAxis;
                        }
                       
                        for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
                                objectTwo.GetOutline()[i].position -= (smallestAxis * overlap);
                        }
                }

                window.clear();
                window.draw(objectTwo.GetOutline());
                window.draw(object.GetOutline());
                window.display();
        }
        return 0;
}

 

And the new, not working SAT code, uses sf::ConvexShape in place of the VertexArray. That's the only change.
// SFML Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "SFML\Graphics.hpp"

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::ConvexShape &shape, int index){
        sf::Vector2f vectorOne = shape.getPoint(index);
    sf::Vector2f vectorTwo;
        if(index >= shape.getPointCount() - 1)
                vectorTwo = shape.getPoint(0);
    else
                vectorTwo = shape.getPoint(index + 1);

    sf::Vector2f normalAxis(-(vectorTwo.y - vectorOne.y), vectorTwo.x - vectorOne.x);
    normalAxis = Normalize(normalAxis);
    return normalAxis;
}

float DotProduct(sf::Vector2f &vectorOne, sf::Vector2f &vectorTwo){
    return vectorOne.x * vectorTwo.x + vectorOne.y * vectorTwo.y;
}

class WorldObject{
public:
        WorldObject(){}
        ~WorldObject(){}

        sf::ConvexShape &GetShape(){ return shape; }
private:
        //this is the only major change, a vertex array to a convex shape
        sf::ConvexShape shape;
};

class Projection{
public:
        Projection(sf::Vector2f &axis, sf::ConvexShape &shape){
                min = DotProduct(axis, shape.getPoint(0));
                max = min;

                for(int i = 1; i < shape.getPointCount(); i++){
                        float proj = DotProduct(axis, shape.getPoint(i));
                        if(proj < min){
                                min = proj;
                        }
                        else if(proj > max){
                                max = proj;
                        }
                }
        }
        ~Projection(){}

        float GetMin(){ return min; }
        float GetMax(){ return max; }

        float GetOverlap(Projection &projection){
                if(projection.GetMin() <= max && max <= projection.GetMax()){
                        return max - projection.GetMin();
                }
                else if(min <= projection.GetMax() && projection.GetMax() <= max){
                        return projection.GetMax() - min;
                }
                else{
                        return 0;
                }
        }
private:
        float min, max;
};

int _tmain(int argc, _TCHAR* argv[]){
        sf::RenderWindow window(sf::VideoMode(500, 500, 32), "Test");

        WorldObject object;
        WorldObject objectTwo;

        object.GetShape().setPointCount(3);
        object.GetShape().setPoint(0, sf::Vector2f(200, 180));
        object.GetShape().setPoint(1, sf::Vector2f(10, 180));
        object.GetShape().setPoint(2, sf::Vector2f(10, 240));
        object.GetShape().setFillColor(sf::Color::White);

        objectTwo.GetShape().setPointCount(4);
        objectTwo.GetShape().setPoint(0, sf::Vector2f(100, 0));
        objectTwo.GetShape().setPoint(1, sf::Vector2f(80, 0));
        objectTwo.GetShape().setPoint(2, sf::Vector2f(80, 20));
        objectTwo.GetShape().setPoint(3, sf::Vector2f(100, 20));
        objectTwo.GetShape().setFillColor(sf::Color::White);

        while(window.isOpen()){
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)){
                        window.close();
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)){
                        objectTwo.GetShape().move(.05, 0);
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
                        objectTwo.GetShape().move(-.05, 0);
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
                        objectTwo.GetShape().move(0, .05);
                }
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
                        objectTwo.GetShape().move(0, -.05);
                }

                if(sf::FloatRect(object.GetShape().getGlobalBounds()).intersects(sf::FloatRect(objectTwo.GetShape().getGlobalBounds()))){
                        std::vector<sf::Vector2f> axesOne;
                        std::vector<sf::Vector2f> axesTwo;

                        //for both shapes, get their axes
                        for(int i = 0; i < object.GetShape().getPointCount(); i++){
                                axesOne.push_back(GetNormalAxis(object.GetShape(), i));
                        }
                        for(int i = 0; i < objectTwo.GetShape().getPointCount(); i++){
                                axesTwo.push_back(GetNormalAxis(objectTwo.GetShape(), i));
                        }

                        //for both sets of axes
                        //project
                        float overlap = 50000000000;
                        sf::Vector2f smallestAxis;
               
                        for(int i = 0; i < axesOne.size(); i++){
                                Projection projectionOne(axesOne[i], object.GetShape());
                                Projection projectionTwo(axesOne[i], objectTwo.GetShape());

                                float o = projectionOne.GetOverlap(projectionTwo);
                                if(o == 0.f){
                                        //no overlap
                                }
                                if(o < overlap){
                                        overlap = o;
                                        smallestAxis = axesOne[i];
                                }
                        }

                        for(int i = 0; i < axesTwo.size(); i++){
                                Projection projectionOne(axesTwo[i], object.GetShape());
                                Projection projectionTwo(axesTwo[i], objectTwo.GetShape());

                                //GetOverlap() always returns 0. Why?
                                float o = projectionOne.GetOverlap(projectionTwo);
                                if(o == 0.f){
                                        //no overlap
                                }
                                if(o < overlap){
                                        overlap = o;
                                        smallestAxis = axesTwo[i];
                                }
                        }

                        sf::Vector2f distance, aPos, bPos;
                        aPos = sf::Vector2f(object.GetShape().getGlobalBounds().left + object.GetShape().getGlobalBounds().width / 2, object.GetShape().getGlobalBounds().top + object.GetShape().getGlobalBounds().height / 2);
                        bPos = sf::Vector2f(objectTwo.GetShape().getGlobalBounds().left + objectTwo.GetShape().getGlobalBounds().width / 2, objectTwo.GetShape().getGlobalBounds().top + objectTwo.GetShape().getGlobalBounds().height / 2);
                        distance = aPos - bPos;

                        if(DotProduct(distance, smallestAxis) < 0.0f){
                                smallestAxis = -smallestAxis;
                        }

                        objectTwo.GetShape().move(-smallestAxis * overlap);
                }

                window.clear();
                window.draw(objectTwo.GetShape());
                window.draw(object.GetShape());
                window.display();
        }

        return 0;
}

 

So the second block of code should also prevent the two shapes from colliding, but nothing happens because I found out that the GetOverlap() function always returns 0.

14
General / Re: How to react to a collision (wall-sliding)?
« on: February 24, 2015, 02:55:42 pm »


Here's the full program again, the problem is that the moving object isn't being pushed back out, rather the moving object seems to disappear off screen. If anybody could take a look at this and offer suggestions that would be much appreciated. Collision detection has made my head almost explode at this point.

The errors were due to a couple of transposed entries. I've updated the code to the working program in case anybody else reading this wants to see the SAT in action. The response is a little buggy, but as long as you don't try  to break this demonstration, it should teach something.

Code: [Select]
// SFML Test.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "SFML\Graphics.hpp"
#include <memory>
#include <iostream>

int loops = 0;

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 vectorOne = shape[index].position;
    sf::Vector2f vectorTwo;
    if(index >= shape.getVertexCount() - 1)
        vectorTwo = shape[0].position;
    else
        vectorTwo = shape[index+1].position;

    sf::Vector2f normalAxis(-(vectorTwo.y - vectorOne.y), vectorTwo.x - vectorOne.x);
    normalAxis = Normalize(normalAxis);
    return normalAxis;
}

float DotProduct(sf::Vector2f &vectorOne, sf::Vector2f &vectorTwo){
    return vectorOne.x * vectorTwo.x + vectorOne.y * vectorTwo.y;
}

class WorldObject{
public:
WorldObject(){}
~WorldObject(){}

sf::VertexArray &GetOutline(){ return outline; }
private:
sf::VertexArray outline;
};

class Projection{
public:
Projection(sf::Vector2f &axis, sf::VertexArray &vertices){
min = DotProduct(axis, vertices[0].position);
max = min;

for(int i = 1; i < vertices.getVertexCount(); i++){
float proj = DotProduct(axis, vertices[i].position);
if(proj < min){
min = proj;
}
else if(proj > max){
max = proj;
}
}
}
~Projection(){}

float GetMin(){ return min; }
float GetMax(){ return max; }

float GetOverlap(Projection &projection){
if(projection.GetMin() <= max && max <= projection.GetMax()){
return max - projection.GetMin();
}
else if(min <= projection.GetMax() && projection.GetMax() <= max){
return projection.GetMax() - min;
}
else{
return 0;
}
}
private:
float min, max;
};

int _tmain(int argc, _TCHAR* argv[]){
sf::RenderWindow window(sf::VideoMode(500, 500, 32), "Test");

WorldObject object;
WorldObject objectTwo;

object.GetOutline().setPrimitiveType(sf::PrimitiveType::Quads);
object.GetOutline().append(sf::Vertex(sf::Vector2f(200, 180)));
object.GetOutline().append(sf::Vertex(sf::Vector2f(180, 180)));
object.GetOutline().append(sf::Vertex(sf::Vector2f(180, 200)));
object.GetOutline().append(sf::Vertex(sf::Vector2f(200, 200)));

objectTwo.GetOutline().setPrimitiveType(sf::PrimitiveType::Quads);
objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(20 + 80, 0)));
objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(0 + 80, 0)));
objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(0 + 80, 20)));
objectTwo.GetOutline().append(sf::Vertex(sf::Vector2f(20 + 80, 20)));

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.GetOutline().getVertexCount(); i++){
objectTwo.GetOutline()[i].position.x += .05;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)){
for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
objectTwo.GetOutline()[i].position.x -= .05;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down)){
for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
objectTwo.GetOutline()[i].position.y += .05;
}
}
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up)){
for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
objectTwo.GetOutline()[i].position.y -= .05;
}
}

//if(sf::FloatRect(object.GetOutline().getBounds()).intersects(sf::FloatRect(objectTwo.GetOutline().getBounds()))){
std::vector<sf::Vector2f> axesOne;
std::vector<sf::Vector2f> axesTwo;
//for both shapes, get their axes
for(int i = 0; i < object.GetOutline().getVertexCount(); i++){
axesOne.push_back(GetNormalAxis(object.GetOutline(), i));
}
for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
//would call collision.getnormalaxis or whatevs
axesTwo.push_back(GetNormalAxis(objectTwo.GetOutline(), i));
}

//for both sets of axes
//project
float overlap = 50000000000;
sf::Vector2f smallestAxis;

for(int i = 0; i < axesOne.size(); i++){
Projection projectionOne(axesOne[i], object.GetOutline());
Projection projectionTwo(axesOne[i], objectTwo.GetOutline());

float o = projectionOne.GetOverlap(projectionTwo);
if(o == 0.f){
//no overlap
}
if(o < overlap){
overlap = o;
smallestAxis = axesOne[i];
}
}

for(int i = 0; i < axesTwo.size(); i++){
Projection projectionOne(axesTwo[i], object.GetOutline());
Projection projectionTwo(axesTwo[i], objectTwo.GetOutline());

float o = projectionOne.GetOverlap(projectionTwo);
if(o == 0.f){
//no overlap
}
if(o < overlap){
overlap = o;
smallestAxis = axesTwo[i];
}
}

for(int i = 0; i < objectTwo.GetOutline().getVertexCount(); i++){
//if it's moving in a negative dir, do this
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
objectTwo.GetOutline()[i].position -= (smallestAxis * overlap);
//otherwise do ditto += ditto
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
objectTwo.GetOutline()[i].position += (smallestAxis * overlap);
}
//}

window.clear();
window.draw(objectTwo.GetOutline());
window.draw(object.GetOutline());
window.display();
loops++;
}

return 0;
}




15
General / Re: How to react to a collision (wall-sliding)?
« on: February 24, 2015, 04:32:28 am »
Right thanks I get what to do there now.

Okay so let's say I have shapes that overlap and I find their MTV. If both shapes are static, then I just move one along the axis for the length of the mtv. But what if one shape has a velocity? How would I alter the shape's velocity so that it doesn't bounce right back into the wall the next frame?

Pages: [1] 2 3 ... 7
anything