Hey guys, my first post on here, I need help with setting up basic collision with a program I just did up. I downloaded sfml about an hour ago, and I have a cube I can move around, and want it to stop moving, when colliding with a stationary cube. The problem most likely lies within one of the loops, or who knows where, but I've had my fill of tinkering with it.

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>

using namespace std;

bool isCollision(int x, int y, int x2, int y2){        //Function I borrowed
	if (abs(x2 - x) > 20 || abs(y2 - y) > 20)
		return false;
	else
		return true;
}

int main()
{
	sf::RenderWindow App(sf::VideoMode(800, 600, 32), "My SFML Window");
	sf::RenderWindow Warning(sf::VideoMode(400, 225, 32), "WARNING!");  //Window that should open on collision
	sf::Shape Rect = sf::Shape::Rectangle(0, 0, 20,	20, sf::Color::Red);
	sf::Shape Rect2 = sf::Shape::Rectangle(50, 0, 70, 20, sf::Color::Blue);
	
	
	while (App.IsOpened())
	{
		sf::Event event;
		while (App.GetEvent(event)) // I now know an easier way to handle these events, but makes no real difference
		{
			if (event.Type == sf::Event::Closed)
				App.Close();
			if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Escape))
				App.Close();
			if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Right))
				Rect.Move(5.0, 0);
			if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Left))
				Rect.Move(-5.0, 0);
			if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Down))
				Rect.Move(0, 5.0);
			if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Up))
				Rect.Move(0, -5.0);
			
			
			int x = Rect.GetPosition().x;
			int y = Rect.GetPosition().y;
			
			int x2 = Rect2.GetPosition().x;
			int y2 = Rect2.GetPosition().y;
			
			isCollision(x, y, x2, y2);
			
			if (isCollision(x, y, x2, y2) == true)
			{
				Warning.Clear(sf::Color::White);
				Warning.Display();
			}
			
		}
		
		App.Clear();
		App.Draw(Rect);
		App.Draw(Rect2);
		App.Display();
	}
	
	return EXIT_SUCCESS;

I got the bool isCollision function from a tut I was watching, but the tut was done in allegro, so I scraped from it what I could. (My logic in using his function was that our cubes are the exact same size, and identical in their properties [one moving one stationary]. The problem must lie, I assume, in how I call the function. Any and all help is appreciated

Dani AI

Generated

After the position/shape issue that fixed, the remaining step is collision resolution — not just detection. Detecting overlap and popping a warning won't stop the moving cube by itself. Two simple, reliable options are: (A) test before you move and skip the move if it would overlap, or (B) apply the move then resolve by undoing only the component that caused penetration. Option B (per-axis rollback) is easy to implement and lets your box slide along faces naturally.

A minimal per-axis example (keeps math independent of any particular SFML call):

struct AABB { float x, y, w, h; };

inline bool overlap(const AABB& a, const AABB& b) {
    return (a.x < b.x + b.w) && (a.x + a.w > b.x) &&
           (a.y < b.y + b.h) && (a.y + a.h > b.y);
}

void moveAndResolve(AABB& player, const AABB& obstacle, float dx, float dy) {
    float oldX = player.x;
    float oldY = player.y;

    // horizontal step + test
    player.x += dx;
    if (overlap(player, obstacle)) {
        player.x = oldX; // cancel horizontal movement
        // zero horizontal velocity if you want it to stop
    }

    // vertical step + test
    player.y += dy;
    if (overlap(player, obstacle)) {
        player.y = oldY; // cancel vertical movement
        // zero vertical velocity if you want it to stop
    }
}

Practical tips: use float/double for positions and velocities to avoid truncation, and update the displayed shape position from your physics coordinates once resolution is done. If movement steps are larger than the obstacle size you may see "tunneling" — either cap step size, sample along the sweep, or implement swept-AABB. For debugging print the box corners or draw debug outlines so you can visually confirm sizes and origins. Finally, verify the collision box exactly matches the visible sprite (origin, width, height) so tests correspond to what you see.

Recommended Answers

All 2 Replies

Yeah, I had a similar problem too when I started playing with SFML.
The solution is simple, but I don't really understand how/why it works...

The main problem is this here -> sf::Shape Rect2 = sf::Shape::Rectangle(50, 0, 70, 20, sf::Color::Blue); .
It should be -> sf::Shape Rect2 = sf::Shape::Rectangle(0, 0, 20, 20, sf::Color::Blue); Rect2.Move(50, 0); .

This works fine for me:

#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>

using namespace std;

bool isCollision(int x, int y, int x2, int y2)
{
    if (abs(x2 - x) > 20 || abs(y2 - y) > 20)
		return false;
	else
		return true;
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(800, 600, 32), "My SFML Window");
    sf::RenderWindow Warning(sf::VideoMode(400, 225, 32), "WARNING!");
    sf::Shape Rect = sf::Shape::Rectangle(0, 0, 20, 20, sf::Color::Red);
    sf::Shape Rect2 = sf::Shape::Rectangle(0, 0, 20, 20, sf::Color::Blue);

    Rect2.Move(50, 0);

    while (App.IsOpened())
    {
        sf::Event event;

        while (App.GetEvent(event))
        {
            if (event.Type == sf::Event::Closed) App.Close();
            if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Escape)) App.Close();
            if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Right)) Rect.Move(5.0, 0);
            if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Left)) Rect.Move(-5.0, 0);
            if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Down)) Rect.Move(0, 5.0);
            if ((event.Type == sf::Event::KeyPressed) && (event.Key.Code == sf::Key::Up)) Rect.Move(0, -5.0);

            int x = Rect.GetPosition().x;
            int y = Rect.GetPosition().y;
            int x2 = Rect2.GetPosition().x;
            int y2 = Rect2.GetPosition().y;

            if (isCollision(x, y, x2, y2))
                Warning.Clear(sf::Color::White);
            else
                Warning.Clear(sf::Color::Black);
        }

        App.Clear();
        App.Draw(Rect);
        App.Draw(Rect2);
        App.Display();
        Warning.Display();
    }
}

You might also want to check this out:

#include <SFML/Graphics.hpp>
#include <iostream>

const int SCREEN_WIDTH=320;
const int SCREEN_HEIGHT=240;
const int BLOCK_SIZE=25;

struct MyRect
{
    double x, y, dx, dy;
    double size;

    sf::Shape sprite;

    MyRect()
    {
        size=BLOCK_SIZE;
        sprite=sf::Shape::Rectangle(0,0,size,size,sf::Color::White);
        x=y=dx=dy=0;
    }

    inline double Top() {return y;}
    inline double Bottom() {return y+size;}
    inline double Left() {return x;}
    inline double Right() {return x+size;}

    void Draw(sf::RenderWindow & window)
    {
        sprite.SetPosition(x,y);
        window.Draw(sprite);
    }
};

bool Collide(MyRect & p, MyRect & o)
{
    double cy=p.Top()-o.Top();
    double cx=p.Left()-o.Left();

    double acy=cy>=0?cy:-cy;
    double acx=cx>=0?cx:-cx;

    if (acy<BLOCK_SIZE && acx<BLOCK_SIZE)
    {
        if (acy>=acx)
        {
            if (cy<0) {if (p.dy>0) p.dy=0; p.y=o.Top()-BLOCK_SIZE;}
            else {p.dy=0; p.y=o.Bottom();}
        }

        if (acx>=acy)
        {
            if (cx<0) {p.dx=0; p.x=o.Left()-BLOCK_SIZE;}
            else {p.dx=0; p.x=o.Right();}
        }

        return true;
    }
    else
        return false;
}

int main()
{
    sf::RenderWindow window(sf::VideoMode(SCREEN_WIDTH,SCREEN_HEIGHT,32),"SFML");
    sf::Event event;

    window.UseVerticalSync(true);

    MyRect p;
    MyRect o;

    o.x=4*BLOCK_SIZE;
    o.y=5*BLOCK_SIZE;

    bool cur_col=false;
    bool prev_col=false;

    bool space_down=false;

    while (window.IsOpened())
    {
        window.GetEvent(event);

        if (event.Type==sf::Event::Closed) window.Close();

        const sf::Input & input=window.GetInput();

        if (input.IsKeyDown(sf::Key::Escape)) window.Close();

        //move

        if (input.IsKeyDown(sf::Key::Left) && !cur_col) p.dx-=0.1;
        if (input.IsKeyDown(sf::Key::Right) && !cur_col) p.dx+=0.1;

        p.x+=p.dx;
        p.y+=p.dy;

        //friction

        p.dx*=0.975;

        //gravity

        if (p.y<SCREEN_HEIGHT-BLOCK_SIZE && !cur_col) p.dy+=0.1;

        //screen limits

        if (p.y<0) {p.dy=0; p.y=0;}
        if (p.y>SCREEN_HEIGHT-BLOCK_SIZE) {p.dy=0; p.y=SCREEN_HEIGHT-BLOCK_SIZE;}
        if (p.x<0) {p.dx=0; p.x=0;}
        if (p.x>SCREEN_WIDTH-BLOCK_SIZE) {p.dx=0; p.x=SCREEN_WIDTH-BLOCK_SIZE;}

        //jump

        if (input.IsKeyDown(sf::Key::Space) && !space_down && !cur_col)
        {
            p.dy=-2.5;
            space_down=true;
        }

        if (!input.IsKeyDown(sf::Key::Space)) space_down=false;

        //collision

        prev_col=cur_col;
        cur_col=Collide(p,o);

        if (cur_col && !prev_col)
            std::cout << "collision!!!" << std::endl;
        if (!cur_col && prev_col)
            std::cout << "free!!!" << std::endl;

        //draw

        window.Clear(sf::Color::Black);
        p.Draw(window);
        o.Draw(window);
        window.Display();
    }
}

It's one of my first SFML experiments :P

Thanks bud, great help!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.