### SFML Help (Math calculation help)

Pages: 12
So im working with SFML and im just messing around with it and learning, and im trying to figure out how to place the corners of 4 squares on the corners of the square in the center. The bottom right one seems to work fine, at least it appears that way but the rest are all messed up. Im pretty bad at math and the code makes it even more confusing for me. Any ideas would be appreciated.

Heres an image

https://ibb.co/qLSBFLX

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103`` ``````#include #include #include int main() { sf::RenderWindow window(sf::VideoMode(1280, 720), "SFML Feature Testing"); sf::Font Arial; Arial.loadFromFile("Resources/Fonts/arial.ttf"); sf::RectangleShape square(sf::Vector2f(100, 100)); square.setFillColor(sf::Color::White); square.setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); sf::RectangleShape cornerSquare_1; sf::RectangleShape cornerSquare_2; sf::RectangleShape cornerSquare_3; sf::RectangleShape cornerSquare_4; cornerSquare_1.setSize(sf::Vector2f(35, 35)); cornerSquare_1.setFillColor(sf::Color::Blue); cornerSquare_2.setSize(sf::Vector2f(35, 35)); cornerSquare_2.setFillColor(sf::Color::Cyan); cornerSquare_3.setSize(sf::Vector2f(35, 35)); cornerSquare_3.setFillColor(sf::Color::Green); cornerSquare_4.setSize(sf::Vector2f(35, 35)); cornerSquare_4.setFillColor(sf::Color::Red); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } if (event.type == sf::Event::Resized) { window.setView(sf::View(sf::FloatRect(0.0f, 0.0f, static_cast(event.size.width), static_cast(event.size.height)))); } } //Set the white square in the dead center of the screen even when its resized square.setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); //DEBUG //cout << "Mouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; //std::cout << "Square X Position: " << square.getPosition().x << " - Square Y Position: " << square.getPosition().y << '\n'; //cout << "Square global bounds height: " << square.getGlobalBounds().height << '\n'; //cout << "Square global bounds left: " << square.getGlobalBounds().left << '\n'; //cout << "Square global bounds top: " << square.getGlobalBounds().top << '\n'; //cout << "Square global bounds width: " << square.getGlobalBounds().width << '\n'; //END DEBUG //Collision detection if (sf::Mouse::getPosition(window).x >= square.getPosition().x && sf::Mouse::getPosition(window).x <= square.getPosition().x + square.getSize().x && sf::Mouse::getPosition(window).y >= square.getPosition().y && sf::Mouse::getPosition(window).y <= square.getPosition().y + square.getSize().y ) { std::cout << "Within white square\n"; } else { //cout << "Not within square\n"; } //cornerSquare.setPosition(sf::Vector2f(sf::Mouse::getPosition(window).x - cornerSquare.getSize().x, sf::Mouse::getPosition(window).y + cornerSquare.getSize().y)); //Set cornerSquare to one corner. //Bottom Right cornerSquare_1.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y)); //Bottom Left cornerSquare_2.setPosition(sf::Vector2f(square.getPosition().x - square.getSize().x, square.getPosition().y + square.getSize().y)); //Top Right cornerSquare_3.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y - square.getSize().y)); //Top Left cornerSquare_4.setPosition(sf::Vector2f(square.getPosition().x - square.getSize().x, square.getPosition().y - square.getSize().y)); window.clear(); window.draw(square); window.draw(cornerSquare_1); window.draw(cornerSquare_2); window.draw(cornerSquare_3); window.draw(cornerSquare_4); window.display(); } return 0; }help with here.``````
Last edited on
Ch1156 wrote:
 ``5051`` ``````//Set the white square in the dead center of the screen even when its resized square.setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2));``````

Note that positions by default refer to the top-left corner of the shape. This means that you have placed the top-left corner of the white square in the middle.

You either need to adjust your logic to take this into account or change the "origin".

https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Transformable.php#a56c67bd80aae8418d13fb96c034d25ec

EDIT: The default is the "top-left corner" and not what I wrote earlier.
Last edited on
You cannot just use the square size. You also need to take the corner sizes into account:
 ``12345678`` `````` //Bottom Left cornerSquare_2.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_2.getSize().x, square.getPosition().y + square.getSize().y)); //Top Right cornerSquare_3.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y - cornerSquare_3.getSize().y)); //Top Left cornerSquare_4.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_4.getSize().x, square.getPosition().y - cornerSquare_4.getSize().y));``````
Not tested!
Thank you! I set the origin of all the squares to the center. But my collision detection for my mouse isnt working anymore, the collision i think is starting at the origin point onward now but im not sure:

Whats really confusing me is just the way you have to write it all out just to do something as simple as position something on screen, like this:

`cornerSquare_1.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y));`

or collision detection like this:

 ``12345`` ``````if (sf::Mouse::getPosition(window).x >= square.getPosition().x && sf::Mouse::getPosition(window).x <= square.getPosition().x + square.getSize().x && sf::Mouse::getPosition(window).y >= square.getPosition().y && sf::Mouse::getPosition(window).y <= square.getPosition().y + square.getSize().y )``````

to me its VERY confusing and harder to understand than actually learning C++ or SFML. Is there an easier way to visualize and use this code?

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109`` ``````#include #include #include int main() { sf::RenderWindow window(sf::VideoMode(1280, 720), "SFML Feature Testing"); sf::Font Arial; Arial.loadFromFile("Resources/Fonts/arial.ttf"); sf::RectangleShape square; square.setSize(sf::Vector2f(300, 300)); square.setFillColor(sf::Color::White); square.setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); square.setOrigin(sf::Vector2f(square.getSize().x / 2, square.getSize().y / 2)); sf::RectangleShape cornerSquare_1; sf::RectangleShape cornerSquare_2; sf::RectangleShape cornerSquare_3; sf::RectangleShape cornerSquare_4; cornerSquare_1.setSize(sf::Vector2f(35, 35)); cornerSquare_1.setFillColor(sf::Color::Blue); cornerSquare_1.setOrigin(sf::Vector2f(cornerSquare_1.getSize().x / 2, cornerSquare_1.getSize().y / 2)); cornerSquare_2.setSize(sf::Vector2f(35, 35)); cornerSquare_2.setFillColor(sf::Color::Cyan); cornerSquare_2.setOrigin(sf::Vector2f(cornerSquare_2.getSize().x / 2, cornerSquare_2.getSize().y / 2)); cornerSquare_3.setSize(sf::Vector2f(35, 35)); cornerSquare_3.setFillColor(sf::Color::Green); cornerSquare_3.setOrigin(sf::Vector2f(cornerSquare_2.getSize().x / 2, cornerSquare_2.getSize().y / 2)); cornerSquare_4.setSize(sf::Vector2f(35, 35)); cornerSquare_4.setFillColor(sf::Color::Red); cornerSquare_4.setOrigin(sf::Vector2f(cornerSquare_2.getSize().x / 2, cornerSquare_2.getSize().y / 2)); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } if (event.type == sf::Event::Resized) { window.setView(sf::View(sf::FloatRect(0.0f, 0.0f, static_cast(event.size.width), static_cast(event.size.height)))); } } //Put debug info in here so i can see the data instead of having it scroll by if (sf::Keyboard::isKeyPressed(sf::Keyboard::P)) { //Set the white square in the dead center of the screen even when its resized square.setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); //DEBUG std::cout << "\nMouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; std::cout << "\nSquare X Position: " << square.getPosition().x << " - Square Y Position: " << square.getPosition().y << '\n'; std::cout << "\nSquare global bounds height: " << square.getGlobalBounds().height << '\n'; std::cout << "Square global bounds left: " << square.getGlobalBounds().left << '\n'; std::cout << "Square global bounds top: " << square.getGlobalBounds().top << '\n'; std::cout << "Square global bounds width: " << square.getGlobalBounds().width << '\n'; //END DEBUG } //Collision detection if (sf::Mouse::getPosition(window).x >= square.getPosition().x && sf::Mouse::getPosition(window).x <= square.getPosition().x + square.getSize().x && sf::Mouse::getPosition(window).y >= square.getPosition().y && sf::Mouse::getPosition(window).y <= square.getPosition().y + square.getSize().y ) { std::cout << "Within white square\n"; } //cornerSquare.setPosition(sf::Vector2f(sf::Mouse::getPosition(window).x - cornerSquare.getSize().x, sf::Mouse::getPosition(window).y + cornerSquare.getSize().y)); //Set cornerSquare to one corner. //Bottom Right cornerSquare_1.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y)); //Bottom Left cornerSquare_2.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_2.getSize().x, square.getPosition().y + square.getSize().y)); //Top Right cornerSquare_3.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y - cornerSquare_3.getSize().y)); //Top Left cornerSquare_4.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_4.getSize().x, square.getPosition().y - cornerSquare_4.getSize().y)); window.clear(); window.draw(square); window.draw(cornerSquare_1); window.draw(cornerSquare_2); window.draw(cornerSquare_3); window.draw(cornerSquare_4); window.display(); } return 0; }``````
Last edited on
Ch1156 wrote:
Thank you! I set the origin of all the squares to the center. But my collision detection for my mouse isnt working anymore

That is not surprising. You decide if positions refer to the center or the top-left corner but you need to be consistent.

Either you need to update your collision detection code to handle center positions or you need to update your drawing code to handle top-left positions.

Note that if you go for center positions you also need to make sure to update the origin if the size of the shape changes (unless you handle that by setting a different "scale").

Ch1156 wrote:
Whats really confusing me is just the way you have to write it all out just to do something as simple as position something on screen, like this:

`cornerSquare_1.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y));`

Ignoring the syntax, it's not very complicated as long as you know whether you're using center positions or top-left positions. What makes it confusing is not knowing or not being consistent. After doing it consistent for a period of time it will eventually become easier to think about.

Note that you can use { } to construct the sf::Vector2f object:

 `` `` ``cornerSquare_1.setPosition({square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y});``

Or you could even pass the x and y coordinates directly as arguments to setPosition:

 `` `` ``cornerSquare_1.setPosition(square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y);``

If you still find the syntax too verbose and hard to read maybe an alternative is to wrap the sf::RectangleShapes into your own rectangle class, then the code could look as simple as:

 ``12345`` ``````// If cornerSquare_1 was an instance of your own rectangle class rather than sf::RectangleShapes cornerSquare_1.set_position(square.x() + square.width(), square.y() + square.height()); // or cornerSquare_1.set_x(square.x() + square.width()); cornerSquare_1.set_y(square.y() + square.height());``````

This could even help you setting the origin consistently by doing it in the constructor of your rectangle class.

If you don't want to create a new class you could instead create some helper functions.

 ``12`` ``````// If you defined helper functions get_x, get_width, etc. cornerSquare_1.set_position({get_x(square) + get_width(square), get_y(square) + get_height(square)});``````

I'm not sure what is a good way to do these things because I have never actually created anything with SFML. I'm just brainstorming. Maybe it's not worth doing what I suggested above. Maybe one gets used to it. But I have to admit that using "x" and "y" to get the width and height seems a little bit confusing at first.

Ch1156 wrote:
or collision detection like this:
 ``12345`` ``````if (sf::Mouse::getPosition(window).x >= square.getPosition().x && sf::Mouse::getPosition(window).x <= square.getPosition().x + square.getSize().x && sf::Mouse::getPosition(window).y >= square.getPosition().y && sf::Mouse::getPosition(window).y <= square.getPosition().y + square.getSize().y )``````

You shouldn't have to repeat this code more than once. If you need to do it in multiple places then create a helper function and use that instead.

It might be a good idea to create a function even if you only call it once (see advice about splitting code into functions below).

Ch1156 wrote:
to me its VERY confusing and harder to understand than actually learning C++ or SFML.

Learning the syntax/API is the easy part. Learning how to program, how to write the logic and to use the "math", etc. is much harder.

As I said earlier, I have never actually created anything with SFML. I have never tried to learn it. I have learned a little while trying to help other people like you, the rest I'm able to look up and test myself because I'm familiar with other graphics/GUI APIs such as SDL, Java Swing, etc.

Ch1156 wrote:
Is there an easier way to visualize and use this code?

You could try splitting the code into functions. By giving the functions nice explanatory names you make the code much more self-explanatory without even having to use comments. It also makes the code more structured because you can more easily focus on one function at a time instead of having everything inside one big complicated function.

Your game loop could look something like this:

 ``123456`` ``````while (window.isOpen()) { handleEvents(); update() render(); }``````

Perhaps not exactly, you might want to pass arguments, use different names or more functions but I hope you get the point.
Last edited on
@ch1156. If you haven't already, I'd suggest investing in a C++ SFML book. There are several available. I'd suggest:
SFML Game Development by Example
https://www.amazon.co.uk/SFML-Development-Example-Raimondas-Pupius/dp/1785287346/ref=sr_1_4

Note that this is a 2015 publication - so only uses C++11/14.

Also when working out things like collision detection etc, you might find it easier to first work out the logic using pen & paper to understand and design and once you're then comfortable with it then code the developed logic - and test.
It's usually always preferable to first design and then code rather than to design as you code.
Last edited on
Thank you all for your responses, I will try to figure something out with it. and yeah I would like to wrap things like the render window in a class so i can instantiate multiple windows for things like the main window, popups etc, and create shape classes and, collision classes etc, but its kind of confusing me because im working with types that are already classes and have member fuctions so im kind of confused how to properly implement a class of classes haha.

As for the SFML book, I actually have that book, I was once contacted by the author a long long time ago about a game project i was working on on the SFML forums that he was interested in, but he couldn't help at the moment as he said he had to write another book, I thought that was kind of cool. Small world.

But anyways I did refactor my code some but my shapes will not appear on screen now. I tried implementing a function pointer since my function returns an sf::RectangleShape and i use it in my code like a variable, but it wont display still. Perhaps im still not quite grasping pointers or i did the pointer syntax wrong. Im unsure.

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162`` ``````#include #include #include #include sf::Text CreateText(const sf::Font& font, int characterSize, const sf::Color& color, float posX, float posY, const std::string& str) { sf::Text text; text.setCharacterSize(characterSize); text.setFont(font); text.setFillColor(color); text.setPosition(sf::Vector2f(posX, posY)); text.setString(str); return text; } sf::RectangleShape* CreateRectangle(float width, float height, const sf::Color& color, float setXPos, float setYPos, float setXOrigin, float setYOrigin) { sf::RectangleShape rectangle; rectangle.setSize(sf::Vector2f(width, height)); rectangle.setFillColor(sf::Color::White); rectangle.setPosition(sf::Vector2f(setXPos, setYPos)); rectangle.setOrigin(sf::Vector2f(setXOrigin, setYOrigin)); return &rectangle; } int main() { sf::RenderWindow window(sf::VideoMode(1280, 720), "SFML Feature Testing"); sf::Font Arial; Arial.loadFromFile("Resources/Fonts/arial.ttf"); std::ostringstream oss; std::istringstream iss; float windowCenterX{ window.getSize().x / 2.0f }; float windowCenterY{ window.getSize().y / 2.0f }; sf::Text MouseXText{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse X Pos: ") }; sf::Text MouseXValue{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse X Value: ") }; sf::Text MouseYText{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse Y Pos: ") }; sf::Text MouseYValue{ CreateText(Arial, 32, sf::Color::White, 204, 30, "Mouse Y Value : ") }; MouseXValue.setPosition(sf::Vector2f(MouseXText.getPosition().x + MouseXText.getGlobalBounds().width, 0.0f)); MouseYText.setPosition(sf::Vector2f(0, MouseXText.getPosition().y + MouseXText.getGlobalBounds().height + 5)); std::cout << "MouseYText Position: " << MouseXText.getPosition().x << '\n'; //Center Square sf::RectangleShape square{ }; CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY, square.getSize().x / 2, square.getSize().y / 2); //Squares //sf::RectangleShape cornerSquare_1 { CreateRectangle(35, 35, sf::Color::Blue, 0, 0, cornerSquare_1.getSize().x / 2.0f, cornerSquare_1.getSize().y / 2.0f) }; //sf::RectangleShape cornerSquare_2 { CreateRectangle(35, 35, sf::Color::Cyan, 0, 0, cornerSquare_2.getSize().x / 2.0f, cornerSquare_2.getSize().y / 2.0f) }; //sf::RectangleShape cornerSquare_3 { CreateRectangle(35, 35, sf::Color::Green, 0, 0, cornerSquare_3.getSize().x / 2.0f, cornerSquare_3.getSize().y / 2.0f) }; //sf::RectangleShape cornerSquare_4 { CreateRectangle(35, 35, sf::Color::Red, 0, 0, cornerSquare_4.getSize().x / 2.0f, cornerSquare_4.getSize().y / 2.0f) }; while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } if (event.type == sf::Event::Resized) { window.setView(sf::View(sf::FloatRect(0.0f, 0.0f, static_cast(event.size.width), static_cast(event.size.height)))); } } //DEBUG //Put debug info in here so i can see the data instead of having it scroll by if (sf::Keyboard::isKeyPressed(sf::Keyboard::P)) { //Set the white square in the dead center of the screen even when its resized square.setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); std::cout << "\nMouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; std::cout << "\nSquare X Position: " << square.getPosition().x << " - Square Y Position: " << square.getPosition().y << '\n'; std::cout << "\nSquare global bounds height: " << square.getGlobalBounds().height << '\n'; std::cout << "Square global bounds left: " << square.getGlobalBounds().left << '\n'; std::cout << "Square global bounds top: " << square.getGlobalBounds().top << '\n'; std::cout << "Square global bounds width: " << square.getGlobalBounds().width << '\n'; std::cout << "\nX Origin: " << square.getOrigin().x << '\n'; std::cout << "Y Origin: " << square.getOrigin().y << '\n'; } oss << sf::Mouse::getPosition(window).x; MouseXValue.setString(oss.str()); oss.str(""); oss << sf::Mouse::getPosition(window).y; MouseYValue.setString(oss.str()); oss.str(""); //std::cout << "\nMouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; //Collision detection /*if (sf::Mouse::getPosition(window).x >= square.getPosition().x && sf::Mouse::getPosition(window).x <= square.getPosition().x + square.getSize().x && sf::Mouse::getPosition(window).y >= square.getPosition().y && sf::Mouse::getPosition(window).y <= square.getPosition().y + square.getSize().y )*/ //TODO - Figure out how to get collision to detect if its within square if (sf::Mouse::getPosition(window).x >= square.getPosition().x && sf::Mouse::getPosition(window).x <= square.getPosition().x + square.getSize().x && sf::Mouse::getPosition(window).y >= square.getPosition().y && sf::Mouse::getPosition(window).y <= square.getPosition().y + square.getSize().y ) { std::cout << "Within white square\n"; } //cornerSquare.setPosition(sf::Vector2f(sf::Mouse::getPosition(window).x - cornerSquare.getSize().x, sf::Mouse::getPosition(window).y + cornerSquare.getSize().y)); //Set cornerSquare to one corner. //Bottom Right //cornerSquare_1.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y)); ////Bottom Left //cornerSquare_2.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_2.getSize().x, square.getPosition().y + square.getSize().y)); ////Top Right //cornerSquare_3.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y - cornerSquare_3.getSize().y)); ////Top Left //cornerSquare_4.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_4.getSize().x, square.getPosition().y - cornerSquare_4.getSize().y)); window.clear(); window.draw(MouseXText); window.draw(MouseXValue); window.draw(MouseYText); window.draw(MouseYValue); window.draw(square); /* window.draw(cornerSquare_1); window.draw(cornerSquare_2); window.draw(cornerSquare_3); window.draw(cornerSquare_4);*/ window.display(); } return 0; }``````
Last edited on
Ch1156 wrote:
I would like to wrap things like the render window in a class so i can instantiate multiple windows for things like the main window, popups etc, and create shape classes and, collision classes etc, but its kind of confusing me because im working with types that are already classes and have member fuctions so im kind of confused how to properly implement a class of classes haha.

Just don't overdo it. Everything don't need to be a class.

You probably will create a lot of classes but don't do it just for the sake of it. The classes should have a purpose.

I know I said earlier that you might want to wrap sf::RectangleShape in your own class to get an easier interface to use but that might be overkill unless you have special requirements.

What you might want to do instead is create some kind of "game object" class (or "entity" or whatever you want to call it) and give that class an easy to use interface instead. Each game object might contain position, hit points, speed, information how to draw it, etc. (the details would depend on your game). Then you could implement collision between game objects instead.

Game objects might contain shapes (e.g. sf::RectangleShape) but not necessarily because it seems like the sf::Shape classes are mainly for drawing. You could just construct them on the fly in your drawing code if you find that easier.

Collision detection doesn't necessarily have to use sf::Shape. Note that SFML has sf::Rect, which is not a sf::Shape, and cannot be drawn. Instead it has functions for checking collisions, both with other sf::Rects and with single (x, y) points.

https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1Rect.php

Later you probably want to draw images (using sf::Texture/sf::Sprite) instead of shapes and then you might want the "collision box" to be smaller than the images to avoid it looking like things collide when they are not touching which could otherwise easily happen if the images contain lots of transparency in the corners.

Note that rectangles are not the only shape that could be used for collision detection. In my game Brum Brum Rally I use circles for collisions between cars. It's not perfect but works good enough in my game because the cars are kind of square/circular in shape. Circles are easy to work with because rotation doesn't matter. All I need to do is check if the distance between two cars is less than 2×radius. Collision with the side of the track is a bit more complicated though.
Last edited on
Ch1156 wrote:
But anyways I did refactor my code some but my shapes will not appear on screen now. I tried implementing a function pointer since my function returns an sf::RectangleShape and i use it in my code like a variable, but it wont display still. Perhaps im still not quite grasping pointers or i did the pointer syntax wrong. Im unsure.

Note that "function pointer" means a pointer that points to a function. What you have here is a function that returns a pointer.

My compiler (GCC) gives me a warning:

If you are not getting a similar warning you probably want to turn on more compiler warnings. With GCC and Clang you can use -Wall to enable this and many other useful warnings. You might also want to use -Wextra.

https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

The problem is that you're returning a pointer to a local variable, but local variables are destroyed when the function ends, so there is no safe way to use the returned pointer because it will at that point point to a non-existing object. It's a so-called dangling pointer.

Either return the sf::RectangleShape object "by value" (this might involve copying)

 ``12345678`` ``````sf::RectangleShape CreateRectangle(float width, float height, const sf::Color& color, float setXPos, float setYPos, float setXOrigin, float setYOrigin) { sf::RectangleShape rectangle; ... return rectangle; }``````

Or allocate it dynamically (smart pointers such as std::unique_ptr can help you with this).

Note that your code doesn't actually use the return value. You will have to assign it to a variable and use it later in the code, otherwise there would be no point in calling the function.

 ``123`` ``````sf::RectangleShape rect = CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY, square.getSize().x / 2, square.getSize().y / 2); ... window.draw(rect);``````

Last edited on
Thanks for the help, I got the smart pointer working and now my shape appears, I noticed i cannot do this though:

`auto square = CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY, square->getSize().x / 2, square->getSize().y / 2, WindowXPos, WindowYPos);`

The errors i get are:

 ```Severity Code Description Project File Line Suppression State Error C3536 'square': cannot be used before it is initialized SFML Game C:\Users\Chay\source\repos\SFML Game\SFML Game\SFML Game.cpp 57 Error (active) E1586 a variable declared with an auto type specifier cannot appear in its own initializer SFML Game C:\Users\Chay\source\repos\SFML Game\SFML Game\SFML Game.cpp 57 Error (active) E1586 a variable declared with an auto type specifier cannot appear in its own initializer SFML Game C:\Users\Chay\source\repos\SFML Game\SFML Game\SFML Game.cpp 57 Error C2660 'CreateRectangle': function does not take 5 arguments SFML Game C:\Users\Chay\source\repos\SFML Game\SFML Game\SFML Game.cpp 57 Error C2100 illegal indirection SFML Game C:\Users\Chay\source\repos\SFML Game\SFML Game\SFML Game.cpp 153 ```

I have to do this instead:

 ``12`` ``````auto square = CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY, 0, 0); square->setOrigin(sf::Vector2f(square->getSize().x / 2, square->getSize().y / 2));``````

Which isnt a big deal but I wanted to know why. It says im not initializing the variable, so is there a way to do that?

Also, why does the smart pointer work and return by value doesnt? The text appears on screen just fine without a pointer to it, and as far as i know both inherit from sf::Drawable, but dont quote me on that haha.
Last edited on
Heres my code:

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162`` ``````//Version 0.0.5 #include #include #include #include sf::Text CreateText(const sf::Font& font, int characterSize, const sf::Color& color, float posX, float posY, const std::string& str) { sf::Text text; text.setCharacterSize(characterSize); text.setFont(font); text.setFillColor(color); text.setPosition(sf::Vector2f(posX, posY)); text.setString(str); return text; } std::unique_ptr CreateRectangle(float width, float height, const sf::Color& color, float setXPos, float setYPos, float setXOrigin, float setYOrigin) { std::unique_ptr rectangle(new sf::RectangleShape); rectangle->setSize(sf::Vector2f(width, height)); rectangle->setFillColor(sf::Color::White); rectangle->setPosition(sf::Vector2f(setXPos, setYPos)); rectangle->setOrigin(sf::Vector2f(setXOrigin, setYOrigin)); return rectangle; } int main() { sf::RenderWindow window(sf::VideoMode(1280, 720), "SFML Feature Testing"); sf::Font Arial; Arial.loadFromFile("Resources/Fonts/arial.ttf"); std::ostringstream oss; std::istringstream iss; float windowCenterX{ window.getSize().x / 2.0f }; float windowCenterY{ window.getSize().y / 2.0f }; sf::Text MouseXText{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse X Pos: ") }; sf::Text MouseXValue{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse X Value: ") }; sf::Text MouseYText{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse Y Pos: ") }; sf::Text MouseYValue{ CreateText(Arial, 32, sf::Color::White, 204, 30, "Mouse Y Value : ") }; MouseXValue.setPosition(sf::Vector2f(MouseXText.getPosition().x + MouseXText.getGlobalBounds().width, 0.0f)); MouseYText.setPosition(sf::Vector2f(0, MouseXText.getPosition().y + MouseXText.getGlobalBounds().height + 5)); std::cout << "MouseYText Position: " << MouseXText.getPosition().x << '\n'; //Center Square auto square = CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY, 0, 0); square->setPosition(sf::Vector2f(square->getSize().x / 2, square->getSize().y / 2)); //Squares //sf::RectangleShape cornerSquare_1 { CreateRectangle(35, 35, sf::Color::Blue, 0, 0, cornerSquare_1.getSize().x / 2.0f, cornerSquare_1.getSize().y / 2.0f) }; //sf::RectangleShape cornerSquare_2 { CreateRectangle(35, 35, sf::Color::Cyan, 0, 0, cornerSquare_2.getSize().x / 2.0f, cornerSquare_2.getSize().y / 2.0f) }; //sf::RectangleShape cornerSquare_3 { CreateRectangle(35, 35, sf::Color::Green, 0, 0, cornerSquare_3.getSize().x / 2.0f, cornerSquare_3.getSize().y / 2.0f) }; //sf::RectangleShape cornerSquare_4 { CreateRectangle(35, 35, sf::Color::Red, 0, 0, cornerSquare_4.getSize().x / 2.0f, cornerSquare_4.getSize().y / 2.0f) }; while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } if (event.type == sf::Event::Resized) { window.setView(sf::View(sf::FloatRect(0.0f, 0.0f, static_cast(event.size.width), static_cast(event.size.height)))); } } //DEBUG //Put debug info in here so i can see the data instead of having it scroll by if (sf::Keyboard::isKeyPressed(sf::Keyboard::P)) { //Set the white square in the dead center of the screen even when its resized square->setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); std::cout << "\nMouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; std::cout << "\nSquare X Position: " << square->getPosition().x << " - Square Y Position: " << square->getPosition().y << '\n'; std::cout << "\nSquare global bounds height: " << square->getGlobalBounds().height << '\n'; std::cout << "Square global bounds left: " << square->getGlobalBounds().left << '\n'; std::cout << "Square global bounds top: " << square->getGlobalBounds().top << '\n'; std::cout << "Square global bounds width: " << square->getGlobalBounds().width << '\n'; std::cout << "\nX Origin: " << square->getOrigin().x << '\n'; std::cout << "Y Origin: " << square->getOrigin().y << '\n'; } oss << sf::Mouse::getPosition(window).x; MouseXValue.setString(oss.str()); oss.str(""); oss << sf::Mouse::getPosition(window).y; MouseYValue.setString(oss.str()); oss.str(""); //std::cout << "\nMouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; //Collision detection /*if (sf::Mouse::getPosition(window).x >= square.getPosition().x && sf::Mouse::getPosition(window).x <= square.getPosition().x + square.getSize().x && sf::Mouse::getPosition(window).y >= square.getPosition().y && sf::Mouse::getPosition(window).y <= square.getPosition().y + square.getSize().y )*/ //TODO - Figure out how to get collision to detect if its within square if (sf::Mouse::getPosition(window).x >= square->getPosition().x && sf::Mouse::getPosition(window).x <= square->getPosition().x + square->getSize().x && sf::Mouse::getPosition(window).y >= square->getPosition().y && sf::Mouse::getPosition(window).y <= square->getPosition().y + square->getSize().y ) { std::cout << "Within white square\n"; } //cornerSquare.setPosition(sf::Vector2f(sf::Mouse::getPosition(window).x - cornerSquare.getSize().x, sf::Mouse::getPosition(window).y + cornerSquare.getSize().y)); //Set cornerSquare to one corner. //Bottom Right //cornerSquare_1.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y + square.getSize().y)); ////Bottom Left //cornerSquare_2.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_2.getSize().x, square.getPosition().y + square.getSize().y)); ////Top Right //cornerSquare_3.setPosition(sf::Vector2f(square.getPosition().x + square.getSize().x, square.getPosition().y - cornerSquare_3.getSize().y)); ////Top Left //cornerSquare_4.setPosition(sf::Vector2f(square.getPosition().x - cornerSquare_4.getSize().x, square.getPosition().y - cornerSquare_4.getSize().y)); window.clear(); window.draw(MouseXText); window.draw(MouseXValue); window.draw(MouseYText); window.draw(MouseYValue); window.draw(*square); /* window.draw(cornerSquare_1); window.draw(cornerSquare_2); window.draw(cornerSquare_3); window.draw(cornerSquare_4);*/ window.display(); } return 0; }``````
 `` `` ``auto square = CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY, square->getSize().x / 2, square->getSize().y / 2, WindowXPos, WindowYPos);``

This defines and initialises a variable square. You can't use the variable that is being defined as part of it's initialisation expression. Hence you can't use square in it's initialisation expression.
Ch1156 wrote:
Also, why does the smart pointer work and return by value doesnt?

It doesn't? Return by value didn't work for me either at first, it crashed, but I thought it was because I used an old version of SFML or because of some kind of standard library incompatibility (I have multiple versions of GCC installed). When I switched to an older compiler (the one that comes with my distribution) it worked so I just assumed it was a problem on my part.

From the discussions I could find on the subject I got the impression that it should work.
You didn't say in what way it didn't work. Did you get an error message? What did it say?

Note that if you return "by value" then square will not be a pointer and you will have to use `.` instead of `->`.

 ```square.setPosition(... ^```
I tested it again without the pointer and it did work, which is odd because i swear it didnt work when it was by value, but thats ok, it needs to be passed by pointer anyways since creating graphics by copy will cause issues and bad performance. I mean one square isnt going to cuase any problems, but if i decided to create a vector of 100 or more of them it will. I tried it before and i didnt get any errors, the program ran but the square didnt draw to the screen.

 This defines and initialises a variable square. You can't use the variable that is being defined as part of it's initialisation expression. Hence you can't use square in it's initialisation expression.

I should have known that, I dont know why it didnt occur to me, thank you.

Is there a way i can see the difference between functions? one without the pointer and one without? Im going to make a vector of 100 sf::recangleShapes and see what it does, im just curious to actually see it. Also i have another strange bug now, the color isnt setting on the squares, theyre all white for some reason, i can set it manually but that defeats the purpose of the function arguments.
Last edited on
Current code.

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171`` ``````//Version 0.0.5 #include #include #include #include sf::Text CreateText(const sf::Font& font, int characterSize, const sf::Color& color, float posX, float posY, const std::string& str) { sf::Text text; text.setCharacterSize(characterSize); text.setFont(font); text.setFillColor(color); text.setPosition(sf::Vector2f(posX, posY)); text.setString(str); return text; } std::unique_ptr CreateRectangle(float width, float height, const sf::Color& color, float setXPos, float setYPos, float setXOrigin, float setYOrigin) { std::unique_ptr rectangle(new sf::RectangleShape); rectangle->setSize(sf::Vector2f(width, height)); rectangle->setFillColor(sf::Color::White); rectangle->setPosition(sf::Vector2f(setXPos, setYPos)); rectangle->setOrigin(sf::Vector2f(setXOrigin, setYOrigin)); return rectangle; } int main() { sf::RenderWindow window(sf::VideoMode(1280, 720), "SFML Feature Testing"); sf::Font Arial; Arial.loadFromFile("Resources/Fonts/arial.ttf"); std::ostringstream oss; std::istringstream iss; float windowCenterX{ window.getSize().x / 2.0f }; float windowCenterY{ window.getSize().y / 2.0f }; sf::Text MouseXText{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse X Pos: ") }; sf::Text MouseXValue{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse X Value: ") }; sf::Text MouseYText{ CreateText(Arial, 32, sf::Color::White, 0.0f, 0.0f, "Mouse Y Pos: ") }; sf::Text MouseYValue{ CreateText(Arial, 32, sf::Color::White, 204, 30, "Mouse Y Value : ") }; MouseXValue.setPosition(sf::Vector2f(MouseXText.getPosition().x + MouseXText.getGlobalBounds().width, 0.0f)); MouseYText.setPosition(sf::Vector2f(0, MouseXText.getPosition().y + MouseXText.getGlobalBounds().height + 5)); std::cout << "MouseYText Position: " << MouseXText.getPosition().x << '\n'; //Center Square auto square{ CreateRectangle(300, 300, sf::Color::White, windowCenterX, windowCenterY, 0, 0) }; square->setOrigin(sf::Vector2f(square->getSize().x / 2, square->getSize().y / 2)); //Squares auto cornerSquare_1 { CreateRectangle(35, 35, sf::Color::Blue, 0, 0, 0, 0) }; cornerSquare_1->setOrigin(sf::Vector2f(cornerSquare_1->getSize().x / 2.0f, cornerSquare_1->getSize().y / 2.0f)); auto cornerSquare_2 { CreateRectangle(35, 35, sf::Color::Cyan, 0, 0, 0, 0) }; cornerSquare_2->setOrigin(sf::Vector2f(cornerSquare_2->getSize().x / 2.0f, cornerSquare_2->getSize().y / 2.0f)); auto cornerSquare_3 { CreateRectangle(35, 35, sf::Color::Green, 0, 0, 0, 0) }; cornerSquare_3->setOrigin(sf::Vector2f(cornerSquare_3->getSize().x / 2.0f, cornerSquare_3->getSize().y / 2.0f)); auto cornerSquare_4 { CreateRectangle(35, 35, sf::Color::Red, 0, 0, 0, 0) }; cornerSquare_4->setOrigin(sf::Vector2f(cornerSquare_4->getSize().x / 2.0f, cornerSquare_4->getSize().y / 2.0f)); while (window.isOpen()) { sf::Event event; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { window.close(); } if (event.type == sf::Event::Resized) { window.setView(sf::View(sf::FloatRect(0.0f, 0.0f, static_cast(event.size.width), static_cast(event.size.height)))); square->setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); } } //DEBUG //Put debug info in here so i can see the data instead of having it scroll by if (sf::Keyboard::isKeyPressed(sf::Keyboard::P)) { //Set the white square in the dead center of the screen even when its resized square->setPosition(sf::Vector2f(window.getSize().x / 2, window.getSize().y / 2)); std::cout << "\nMouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; std::cout << "\nSquare X Position: " << square->getPosition().x << " - Square Y Position: " << square->getPosition().y << '\n'; std::cout << "\nSquare global bounds height: " << square->getGlobalBounds().height << '\n'; std::cout << "Square global bounds left: " << square->getGlobalBounds().left << '\n'; std::cout << "Square global bounds top: " << square->getGlobalBounds().top << '\n'; std::cout << "Square global bounds width: " << square->getGlobalBounds().width << '\n'; std::cout << "\nX Origin: " << square->getOrigin().x << '\n'; std::cout << "Y Origin: " << square->getOrigin().y << '\n'; } oss << sf::Mouse::getPosition(window).x; MouseXValue.setString(oss.str()); oss.str(""); oss << sf::Mouse::getPosition(window).y; MouseYValue.setString(oss.str()); oss.str(""); //std::cout << "\nMouse X: " << sf::Mouse::getPosition(window).x << " Mouse Y: " << sf::Mouse::getPosition(window).y << '\n'; //Collision detection /*if (sf::Mouse::getPosition(window).x >= square->getPosition().x && sf::Mouse::getPosition(window).x <= square->getPosition().x + square->getSize().x && sf::Mouse::getPosition(window).y >= square->getPosition().y && sf::Mouse::getPosition(window).y <= square->getPosition().y + square->getSize().y )*/ //TODO - Figure out how to get collision to detect if its within square if (sf::Mouse::getPosition(window).x >= square->getPosition().x && sf::Mouse::getPosition(window).x <= square->getPosition().x + square->getSize().x && sf::Mouse::getPosition(window).y >= square->getPosition().y && sf::Mouse::getPosition(window).y <= square->getPosition().y + square->getSize().y ) { std::cout << "Within white square\n"; } //cornersquare->setPosition(sf::Vector2f(sf::Mouse::getPosition(window).x - cornersquare->getSize().x, sf::Mouse::getPosition(window).y + cornersquare->getSize().y)); //Set cornerSquare to one corner. //Bottom Right cornerSquare_1->setPosition(sf::Vector2f(square->getPosition().x + square->getSize().x, square->getPosition().y + square->getSize().y)); ////Bottom Left cornerSquare_2->setPosition(sf::Vector2f(square->getPosition().x - cornerSquare_2->getSize().x, square->getPosition().y + square->getSize().y)); ////Top Right cornerSquare_3->setPosition(sf::Vector2f(square->getPosition().x + square->getSize().x, square->getPosition().y - cornerSquare_3->getSize().y)); //Top Left cornerSquare_4->setPosition(sf::Vector2f(square->getPosition().x - cornerSquare_4->getSize().x, square->getPosition().y - cornerSquare_4->getSize().y)); window.clear(); window.draw(MouseXText); window.draw(MouseXValue); window.draw(MouseYText); window.draw(MouseYValue); window.draw(*square); window.draw(*cornerSquare_1); window.draw(*cornerSquare_2); window.draw(*cornerSquare_3); window.draw(*cornerSquare_4); window.display(); } return 0; }``````
I think shapes are relatively cheap to construct and copy. If you just construct the shape once at the start of your program one extra copy is unlikely to make much of a difference. Dynamic allocations have overhead and are less cache friendly so it's not a given that it would perform better. You might want to test with many shapes, but if I just move square inside the loop so that it is constructed each iteration I still get the same FPS as before (around 300).

sf::Texture and sf::Font might be a different story. It looks like they might be more costly to construct and copy but I haven't tested it. Still might not be a problem if it's not something you do repeatedly.
Last edited on
Note that
 `` `` ``auto square = CreateRectangle(...``
will probably not need to copy the rectangle object even if it's returned by value. The return value will probably be constructed directly inside square. Look up copy elision / NRVO if you're interested.
Last edited on
Ch1156 wrote:
Also i have another strange bug now, the color isnt setting on the squares, theyre all white for some reason, i can set it manually but that defeats the purpose of the function arguments.

You are setting it to white! The color parameter is never used.

GCC wrote:
warning: unused parameter ‘color’ [-Wunused-parameter]
Last edited on
Ah, my bad, thats embarrassing, I fixed the color thing and now it works. Im going to work on figuring out the positioning issue since the origin is the center of the square now. Ive been thinking about it and if i just do the calculations starting at the center i might be able to figure it out.

hmmm, ill have to do some testing. Maybe the shapes themselves are cheap but when i put textures on them they may become expensive, im unsure, i'll have to test it with some textures.

Also is there any way to do this:

`auto cornerSquare_1 { CreateRectangle(35, 35, sf::Color::Blue, 0, 0, cornerSquare_1->getSize().x / 2.0f, cornerSquare_1->getSize().y / 2.0f) };`

Even though the variable is technically undeclared at that point? writing the set origin function for each seems like a waste of code when i can just do it in the function call.
Last edited on
Pages: 12