I want to be able to render sf::CircleShape
(representing pointwise charges) when pressing mouse buttons on the window. The problem is easy enough, however the shapes that I want to draw are attributes of a class Charge
. The Scene
class implements window management and event polling/ rendering methods and it has an attribute std::vector<Charge> distribution
.
The idea is to update the distribution
variable everytime the event sf::Mouse::isButtonPressed
is recorded and then draw the charges' shapes within such vector. For some reason I cannot make it work and I think it's due to the object being created and destroyed within the event loop.
I have a main that looks like this
#include "Scene.h"
int main(){
Scene scene;
while(scene.running())
{
scene.update();
scene.render();
}
return 0;
}
with the header Scene.h
declaring the class methods for window management and event polling
#include "Charge.h"
class Scene
{
private:
sf::RenderWindow* window;
sf::Event event;
std::vector<Charge> distribution;
public:
Scene();
virtual ~Scene();
bool running();
void polling();
void render();
void update();
};
The definitions of the methods instantiated in the game loop are
void Scene::update(){this -> polling();}
void Scene::polling()
{
while(this -> window -> pollEvent(this -> event))
{
switch(this -> event.type)
{
case sf::Event::Closed: this -> window -> close();
break;
case sf::Event::MouseButtonPressed:
this -> distribution.push_back(Charge(*this -> window, sf::Mouse::getPosition(*this -> window));
std::cout << "Distribution size = " << distribution.size() << "\n";
break;
}
}
}
void Scene::render()
{
this -> window -> clear(sf::Color::Black);
for(auto charge: this -> distribution)
{
charge.render(*this -> window);
}
this -> window -> display();
}
The window
object is instatiated in the cosntrutor of Scene
. Now Charge.h
declares the class
class Charge
{
private:
sf::CircleShape shape;
public:
Charge(const sf::RenderWindow& window, sf::Vector2i position);
virtual ~Charge();
void render(sf::RenderTarget& target);
};
and the definition of its methods is the following
Charge::Charge(const sf::RenderWindow& window, sf::Vector2i position)
{
std::cout << "Charge's object created!" << std::endl;
this -> shape.setOrigin(sf::Vector2f(static_cast<float>(position.x), static_cast<float>(position.y)));
this -> shape.setFillColor(sf::Color(255,50,50));
this -> shape.setRadius(25.f);
}
Charge::~Charge(){std::cout << "Charge's object destroyed!" << std::endl;}
void Charge::render(sf::RenderTarget& target)
{
target.draw(this -> shape);
}
I added printing on terminal in the constructor and destructor. The execution of the program does not render any of the objects' shapes when mouse buttons are pressed. The terminal however reports
Charge's object created! # <-- Here I pressed the mouse's button
Charge's object destroyed!
Distribution size = 1
Charge's object destroyed!
Charge's object destroyed!
Charge's object destroyed!
Charge's object destroyed!
Charge's object destroyed!
Charge's object destroyed!
Charge's object destroyed! # <-- And it goes on and on as long as the window is not closed.
I tried to approach the problem in various ways but none have worked so far. Any idea?
Your range-based for loop uses auto
instead of auto&
, thus you're constantly creating temporary copies of the Charge
class.
Additionally, you shouldn't mix sf::Mouse::getPosition()
with events. The mouse events already provide the position: event.mouseButton.x
/ event.mouseButton.y
.