Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Cannot set pointer to an sf::RectangleShape  (Read 3331 times)

0 Members and 1 Guest are viewing this topic.

dd

  • Newbie
  • *
  • Posts: 10
    • View Profile
Cannot set pointer to an sf::RectangleShape
« on: July 18, 2024, 08:44:30 pm »
I'm making a physics engine, as of current I'm implementing gravity. I've implemented it fine, however I preferably want multiple shapes to play around with. So, I created a function
std::vector<RectangleData> CreateRectangle(int Amount, std::vector<sf::Vector2f> Pos);
, in which RectangleData is a union consisting of an sf::RectangleShape pointer, bounciness of the rectangle, it's current fall speed, and it's terminal velocity.
So then, in the function, I create the RectangleShape, set the pointer in the RectangleData union to be pointing to it, set all the other values, add it to the return array, however when drawing it, it segfaults. After testing this, it appears to be segfaulting as the pointer in the union is a null pointer, despite I set it to be pointing. Here is my code:
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>

union RectangleData {
        sf::RectangleShape *Rectangle=nullptr;
        double RectangleTerminalVelocity;
        double RectangleBouncyness;
        double RectangleFallSpd;
};

bool IsInside(sf::Vector2f Size, sf::Vector2i Pos1, sf::Vector2f Pos2);
std::vector<RectangleData> CreateRectangle(int Amount, std::vector<sf::Vector2f>Pos);
//void HandleRectanglePhysics(std::vector<*sf::RectangleShape> Rectangles, std::vector<double> TerminalVelocity, std::vector<double>Bouncyness);

int main() {
        std::vector<RectangleData> Rectangles = CreateRectangle(1, {sf::Vector2f(100, 0)});
        double WantedFps = 60;
        double AccelerationSpd = 1.5;
        double Rectangle1TerminalVelocity =4;
        double Rectangle1Bouncyness = 1.525;
        sf::RenderWindow Window(sf::VideoMode(800, 600), "Physics Engine");
        sf::RectangleShape Rectangle1(sf::Vector2f(50, 50));
        double Rectangle1FallSpd =0;
        sf::Clock Frame;
        while (Window.isOpen()){
                if (Frame.getElapsedTime() >= sf::seconds(1/WantedFps)){
                        if (sf::Mouse::isButtonPressed(sf::Mouse::Left) && IsInside(Rectangle1.getSize(), sf::Mouse::getPosition(Window), Rectangle1.getPosition())){
                                Rectangle1.setPosition(static_cast<sf::Vector2f>(sf::Mouse::getPosition(Window)));
                                Rectangle1.move(sf::Vector2f(Rectangle1.getSize().x/-2, Rectangle1.getSize().y/-2));
                                Rectangle1FallSpd = 0;
                        }
                        else {
                                Rectangle1FallSpd += AccelerationSpd/WantedFps;
                                Rectangle1.move(sf::Vector2f(0, Rectangle1FallSpd));
                                if (Rectangle1FallSpd >= Rectangle1TerminalVelocity){
                                        Rectangle1FallSpd = Rectangle1TerminalVelocity;
                                }
                        }
                        if (Rectangle1.getPosition().y >= 550){
                                Rectangle1.setPosition(sf::Vector2f(Rectangle1.getPosition().x, 550));
                                Rectangle1FallSpd -= Rectangle1FallSpd*Rectangle1Bouncyness;
                        }
                        sf::Event Event;
                        while (Window.pollEvent(Event)){
                                if (Event.type == sf::Event::Closed){
                                        Window.close();
                                }
                        }
                        Window.clear();
                        Window.draw(Rectangle1);
                        //Window.draw(*Rectangles.at(0).Rectangle);
                        Window.display();
                        Frame.restart();
                }
        }
}

bool IsInside(sf::Vector2f Size, sf::Vector2i Pos1i, sf::Vector2f Pos2){
        sf::Vector2f Pos1 = static_cast<sf::Vector2f>(Pos1i);
        if (Pos2.x + Size.x >= Pos1.x && Pos2.y + Size.y >= Pos1.y && Pos1.x >= Pos2.x && Pos1.y >= Pos2.y){
                return true;
        }
        return false;
}      

std::vector<RectangleData> CreateRectangle(int Amount, std::vector<sf::Vector2f> Pos){
        std::vector<RectangleData> RectangleDataVec;
        for (int i=0; i<Amount; i++){
                sf::RectangleShape RectangleInstance(sf::Vector2f(50, 50));
                RectangleInstance.setPosition(Pos.at(i));
                RectangleData RectInstance;
                RectInstance.Rectangle = &RectangleInstance;
                RectInstance.RectangleTerminalVelocity = 4;
                RectInstance.RectangleFallSpd = 0;
                RectInstance.RectangleBouncyness=1.525;
                RectangleDataVec.push_back(RectInstance);
                std::cout << RectInstance.Rectangle << "\n" << &RectangleInstance;
        }
        return RectangleDataVec;
}
 

vokazoo

  • Newbie
  • *
  • Posts: 18
    • View Profile
    • Email
Re: Cannot set pointer to an sf::RectangleShape
« Reply #1 on: July 18, 2024, 10:08:36 pm »
Change keyword union to struct.

Unions have only one active member, meaning when execution gets to line
RectInstance.RectangleTerminalVelocity = 4;
pointer RectInstance.Rectangle is invalidated.

Secondly, you're assigning pointer RectInstance.Rectangle to point to the address of local variable RectangleInstance, and later dereferencing that pointer which is undefined behaviour. Create RectangleInstance* with new operator instead, just don't forget to free the memory when you finish with it. Or create sf::RectangleShape on stack but ensure that it doesn't go out of scope as long any pointer pointing to it is in use, but the best approach would be to ditch pointers and declare RectangleData::Rectangle as sf::RectangleShape, that way it's much simpler and safer.

That should be enough to make the program run properly, but there are other improvements to be done, most notably instead of returning a copy of vector from function, send vector reference as function argument.

At the end, it should look something like this:
struct RectangleData {
    sf::RectangleShape Rectangle;
    double RectangleTerminalVelocity;
    double RectangleBouncyness;
    double RectangleFallSpd;
};
int main() {
    std::vector<RectangleData> Rectangles;
    CreateRectangle(Rectangles, { sf::Vector2f(100.f, 0.f) });
    //...
}
void CreateRectangle(std::vector<RectangleData>& vec, const std::vector<sf::Vector2f>& Pos) {
    for (std::size_t i = 0; i < Pos.size(); i++) {
        RectangleData RectInstance;
        RectInstance.Rectangle.setPosition(Pos.at(i));
        RectInstance.Rectangle.setSize({ 50.f, 50.f });
        RectInstance.RectangleTerminalVelocity = 4;
        RectInstance.RectangleFallSpd = 0;
        RectInstance.RectangleBouncyness = 1.525;
        vec.push_back(RectInstance);
    }
}