SFML drawing elements of vector of pointers - c++

here is the structure of my program:
class Game
{
public:
unsigned int progressFlags;
sf::RenderWindow appWindow;
Screen* currentScreen;
Game(const unsigned int& width, const unsigned int& height,
const unsigned int& bitsPerPixel, const std::string& windowName);
~Game();
void drawScreen();
};
Game contains a Screen which is defined as:
class Screen
{
public:
std::vector<sf::Drawable*> sceneElements;
sf::Sprite backgroundSprite;
Screen();
virtual ~Screen();
protected:
sf::Texture backgroundTexture;
};
Elements of std::vector sceneElements are collected from screens like this:
sceneElements.push_back(&backgroundSprite);
At last, I am trying to draw all my graphic objects using a simple method:
void Game::drawScreen()
{
for (unsigned int i = 0; i < currentScreen->sceneElements.size(); i++)
appWindow.draw(*currentScreen->sceneElements(i));
}
But appWindow.draw() fails. I think it is something about dereferencing pointers (some basic c++ knowledge I cant just remember), but I don't know how to fix it. I would appreciate any help.

I'd just derive your custom classes from sf::Drawable (and potentially sf::Transformable). This way drawing hierarchically is very easy and basically done by SFML. The following snippets are written from memory; there might be typos. :)
You'll just have to subclass your Screen class:
class Screen : public sf::Drawable
{
public:
std::vector<sf::Drawable*> sceneElements;
sf::Sprite backgroundSprite;
Screen();
virtual ~Screen();
virtual void draw(sf::RenderTarget &rt, sf::RenderStates states) const;
protected:
sf::Texture backgroundTexture;
};
Inside draw() you'd just iterate over all your elements (similar to the way you do already):
void draw(sf::RenderTarget &rt, sf::RenderStates states) const
{
for (const auto &e : sceneElements)
rt.draw(*e, states);
}
Here we're dereferencing once to get from a pointer back to the object, which is then passed by reference (where inheritance does the rest).
Game::drawScreen() becomes more simple as well:
void Game::drawScreen()
{
appWindow.draw(*currentScreen);
}
Once again, derefrencing once to go from the pointer to the actual object (passed by reference).
Also note that your original design violates encapuslation, by Game having to know how to work with stuff that's inside your Scene. So if you change things inside Scene, you'll have to adjust Game accordingly. Using inheritance, you're avoiding this issue.

Related

Non standard syntax - Use & to create a pointer to a member : C++ function pointer to member

I am creating a spirograph application, and have a simple GUI class, which produces and manages buttons - you can call this functions with a custom function pointer upon clicking on them.
I also have an Engine class, which manages the drawing of my spirograph, and the GUI buttons.
I would like to create a button that has a pointer to a member function from within the engine class, but I keep getting an error.
The error is coming when I try to create a button with a function pointer from the Engine class.
Here is the problem in a nutshell, as suggested by Frank in the comments (thank you)
class Engine;
typedef void(Engine::*enginefunc)(void);
class Engine
{
void cb();
void register_callback(enginefunc ptr);
void foo() {
register_callback(cb);
}
};
Here is my engine class:
Engine.h
class Engine : public GUI
{
private:
//....
public:
Engine(sf::Vector2f* mousepos);
//...
//...inherited a function from GUI called addbutton.
};
Engine::Engine(sf::Vector2f* mousepos)
:GUI(mousepos)
{
//THIS IS THE LINE WHICH PRODUCES THE ERROR. I AM TRYING TO PASS THE CHANGE POINT FUNCTION INTO THE GUI BUTTON.
addbutton(sf::Vector2f{ 100,50 }, sf::Vector2f{ 200,100 }, "Button", sf::Color::Red, sf::Color::Blue, changepoint);
}
Here is the GUI.h (Contains the addbutton function which is causing the error)
class Engine;
typedef void(Engine::* enginefunc)(void);
class GUI : public sf::Drawable
{
private:
//...
public:
GUI(sf::Vector2f* mousepos);
void addbutton(const sf::Vector2f& position, const sf::Vector2f& dimension, const std::string& text, sf::Color initcolor, sf::Color highlightcolor, enginefunc ptr);
//other member funcs..
};
Here is the GUI::addbutton function
void GUI::addbutton(const sf::Vector2f& pos, const sf::Vector2f& size, const std::string& text, sf::Color before, sf::Color after, enginefunc ptr)
{
buttons.emplace_back(pos, size, text, before, after, ptr);
}
So the addbutton function creates a GUIButton class, which stores the function ptr. When the button is clicked, that function pointer is called via std::invoke.
Here is my GUIButton.h
class Engine;
typedef void(Engine::*enginefunc)(void);
class GUIButton : public sf::RectangleShape
{
public:
GUIButton(const sf::Vector2f& position, const sf::Vector2f& size, const std::string& text, sf::Color initcolor, sf::Color highlightcolor, enginefunc ptr);
void action(Engine& e);
//other members...
private:
//other members...
enginefunc actionptr;
};
As you can see, the enginefunc GUIButton::actionptr is the function pointer which will be actioned when the button is pressed.
Here is the GUIButton::action() function which calls the function:
void GUIButton::action(Engine& e)
{
if (actionptr != nullptr)
{
std::invoke(actionptr, e);
}
}
I do not understand what I am doing wrong. I understand that a pointer to member function must be tied to a specific object, which is why I have taken in the Engine object as reference.
Any suggestions?
You should just use a std::function instead. In this case, best practices here would call for using a lambda to bind this.
The equivalent of your code:
class Engine;
typedef void(Engine::*enginefunc)(void);
class Engine
{
Engine();
void changepoint();
void addbutton(enginefunc ptr);
};
Engine::Engine() {
addbutton(changepoint);
}
Becomes:
class Engine
{
Engine();
void changepoint();
void addbutton(std::function<void()> ptr);
};
Engine::Engine() {
addbutton([this](){changepoint();});
}

What is the purpose of a virtual operator ()() here?

I'm trying to modify code I found, but I'm blocked by my lack of understanding of the purpose, importance, and/or relevance of this virtual operator:
Can someone provide insight as to why this operator is necessary or useful?
Am I right in thinking it takes parentItem(), rect_, and resizer_ as parameters, then modifies the value of resizer_?
Constructor in .h:
virtual void operator()(QGraphicsItem* item, const QRectF& rect) = 0;
Call in .cpp:
(*resizer_)(parentItem(), rect_);
Trimmed context for the constructor for reference:
class SizeGripItem : public QGraphicsItem
{
private:
class HandleItem : public QGraphicsRectItem
{
public:
HandleItem(int positionFlags, SizeGripItem* parent);
private:
SizeGripItem* parent_;
};
public:
class Resizer
{
public:
virtual void operator()(QGraphicsItem* item,
const QRectF& rect) = 0;
};
SizeGripItem(Resizer* resizer = 0, QGraphicsItem* parent = 0);
virtual ~SizeGripItem();
private:
void doResize();
QRectF rect_;
Resizer* resizer_;
};
The Resizer is a broken attempt at a polymorphic functor (function object). Such an idiom was useful before C++11. It's broken because such functors are useless without a virtual destructor. It should have looked as follows:
class Resizer {
public:
virtual void operator()(QGraphicsItem* item, const QRectF& rect) = 0;
virtual ~Resizer() {}
};
Such objects are callable:
void invokeResizer(Resizer * resizer, QGraphicsItem * item, const QRectF & rect) {
(*resizer)(item, rect);
}
The above will execute the method operator()(QGraphicsItem*,const QRectF&) on the resizer object.
In modern code, instead of such hacks, one should use std::function<void(QGraphicsItem*, const QRectF &)>.
Regarding point 2, consider this line:
(*resizer_)(parentItem(), rect_);
resizer_ is likely a pointer to an object of an unknown type T, thus *resizer is a reference to an object of the same type T.
If it has a definition for operator() that accepts two parameters having types (let me say) decltype(parentItem()) and decltype(rect_), you can invoke it as it happens in the example.
In other terms, it's equivalent to:
resizer_->operator()(parentItem(), rect_);
It doesn't modify the value of resizer_ at all.
Can someone provide insight as to why this operator is necessary or useful?
Well, it mostly depends on the context and the actual problem it aims to solve.
It's hard to say from a line of code.
If you find it useless, don't use it. That's all.

C++: Use pointer from abstract class for accessing method of derived classes; derived class apears to be abstract as well

I have looked for 2 hours now (mainly on this site) to understand my problem I have while coding in C++. I have a abstract base class which looks like this:
Screen.hpp
#include <SFML/Graphics.hpp>
class Screen {
public:
virtual ~Screen();
virtual void Init() const = 0;
virtual void Render(sf::RenderWindow &window) const = 0;
virtual void Update(sf::RenderWindow &window, sf::Time &deltaTime) const = 0;
virtual void EventTriggered(sf::RenderWindow &window, sf::Event &event) const = 0;
};
Next I have declared a class which derives from the base class:
Splashscreen.hpp
#include "Screen.hpp"
class Splashscreen : public Screen {
public:
Splashscreen();
~Splashscreen();
void Init();
void Update(sf::RenderWindow &window, sf::Time &deltaTime);
void Render(sf::RenderWindow &window);
void EventTriggered(sf::RenderWindow &window, sf::Event &event);
private:
sf::Sprite *_splashSprite;
};
And finally I want to create a new Splashscreen object and assign the address to a pointer from the base class:
void Game::Init() {
Screen* ptrScreen = new Splashscreen;
_displayMgr.AddScreen("Splash", ptrScreen);
_displayMgr.ChangeScreen("Splash");
}
As I mentioned before, I looked this problem up already and found a ton of solutions and came up with this what I have now. But I still get an error in the line
Screen* ptrScreen = new Splashscreen;
while compiling that says following:
error: invalid new-expression of abstract class type 'Splashscreen'
I just don't understand this, because I have defined all declared methods that are mentioned in Splashscreen.hpp right here:
Splashscreen.cpp
#include "SplashScreen.hpp"
Splashscreen::Splashscreen() {}
Splashscreen::~Splashscreen() {}
void Splashscreen::Init() {}
void Splashscreen::Update(sf::RenderWindow &window, sf::Time &deltaTime) {}
void Splashscreen::Render(sf::RenderWindow &window) {}
void Splashscreen::EventTriggered(sf::RenderWindow &window, sf::Event &event) {}
I hope someone can help me and forgive me, if this question was already to many times. But it is hard to change your "mind of programming" when you change from Java to C++. But I already like C++ better :) It is challenging and I like that a lot.
[EDIT]:
I only changed the following:
class Splashscreen : public Screen {
public:
Splashscreen();
~Splashscreen();
void Init() const;
void Update(sf::RenderWindow &window, sf::Time &deltaTime) const;
void Render(sf::RenderWindow &window) const;
void EventTriggered(sf::RenderWindow &window, sf::Event &event) const;
private:
sf::Sprite *_splashSprite;
};
The others are still the same.
From Screen:
virtual void Init() const = 0;
From Splashscreen:
void Init();
One of them is const, the other is not. You should remove const from Screen or add it to Splashscreen, whichever makes sense.
All your pure virtual functions in Screen are defined as const . This trailing const is not only an indication that the function will not modifiy the object, but it is entirely part of the signature.
Unfortunately, the functions with the same name in Screesplash are not defined as const. So these functions are not an override of your pure virtuals, but additional functions. This means that your pure virtual functions are still not overriden and your Screensplash is hence still an abstract class that can't be instantiated.
To solve your issue, just add the trailing const keyword behind your functions.
To avoid similar issues in the future, take the habit of using the override keyword to tell the compiler your intention. If by accident you have a mismatch in the signature, the compiler will immediately tell you that your function was not an override as you thought.
class Splashscreen : public Screen {
public:
...
void Init() const override;
void Update(sf::RenderWindow &window, sf::Time &deltaTime) const override;
void Render(sf::RenderWindow &window) const override;
void EventTriggered(sf::RenderWindow &window, sf::Event &event) const override;
...
};

graphic drawing class organisation

I have a basic 4x20 character LCD that I would like to use for displaying a menu with buttons using an Arduino as the driver (limited standard library support).
Example LCD menu and buttons
I'm thinking of producing an interface class GraphicObject that all graphical objects then inherit from (such as Button, MenuItem etc.). It seems logical that the GraphicObject class should have a draw method which can be overridden.
At the moment, I have a class called Lcd which covers the low level drawing of text and character positioning. In order to draw anything, I will need access to one of these Lcd objects. If I include a pointer to the Lcd object within my GraphicObject or derived objects, I couple them and make them Lcd only objects. If I change the type of display device these classes aren't suitable any more.
How can the classes be organised to keep them loosely coupled and allow for a change in display types at a later date? Should I have LCDButton LCDMenuItem which then inherit from a Button and MenuItem interface, then create additional objects for the other display device (OtherDisplayButton OtherDisplayMenuItem)?
Any suggested reading? I've looked at many examples, but none of them seem to go into details about the function of a draw method and whether the device should be accessed directly or through another controlling object.
Thanks
Edit 1
Brief code idea overview
#include "Arduino.h"
class Lcd {
public:
struct Parameters {
uint_fast8_t numberLines;
uint_fast8_t numberCharacters;
// uint_fast8_t* lineOffsets;
Print* serial; // Can be any Serial device (all inherit from Print).
};
protected:
Parameters parameters_;
const uint_fast8_t escapeCode_ = 0x1B;
const uint_fast8_t directCode_ = 0xFE;
void sendCommand_(uint_fast8_t command, uint_fast8_t parameter = 0);
void sendCommandDirect_(uint_fast8_t command);
public:
Lcd(Parameters parameters);
void clearDisplay(void);
void moveCursor(uint_fast8_t line, uint_fast8_t character);
void resetDisplay(void);
void customCharacter(const uint_fast8_t address,
const uint_fast8_t characterMap[8]);
void write(uint8_t character);
// Boilerplate print forwarders.
void print(const char character);
void print(const String &string);
void print(const char string[]);
// Boilerplate println forwarders.
void println(const char character);
void println(const String &string);
void println(const char string[]);
void println(void);
};
class GraphicObject {
virtual void draw(void)=0;
};
class Button: public GraphicObject {
public:
typedef void (*buttonAction)(void);
virtual void setText(const String text)=0;
virtual const String getText() =0;
virtual bool isActive()=0;
virtual void setActive(bool)=0;
virtual void setAction(buttonAction action)=0;
};
class MenuItem: public Button {
public:
typedef void (*menuAction)(void);
virtual MenuItem* parentItem()=0;
virtual const MenuItem* addItem(String text, menuAction action)=0;
};
class VScrollbar: public GraphicObject {
public:
virtual void setAtTop(bool atTop);
virtual void setAtBottom(bool atBottom);
};
class LcdButton: public Button {
private:
Lcd* lcd_;
String text_;bool active_;
public:
LcdButton(Lcd* lcd);
void draw(void);
void setText(String text);
const String getText();bool isActive();
void setActive(bool);
void setAction(Button::buttonAction action);
};
class LcdWindow: public GraphicObject {
private:
LcdButton* lcdButtons_ = nullptr;
public:
enum class Position
: uint_fast8_t {
LEFT,
RIGHT
};
bool addButton(LcdButton* lcdButton, uint_fast8_t line, uint_fast8_t offset);
bool addVScrollbar(VScrollbar* vScrollbar, Position position);
void draw();
};
int main(void) {
Lcd::Parameters lcdParameters;
lcdParameters.numberCharacters = 20;
lcdParameters.numberLines = 4;
lcdParameters.serial = &Serial1;
Lcd lcd = Lcd(lcdParameters);
LcdButton myButton(&lcd);
myButton.setText("Select");
myButton.setActive(true);
LcdWindow lcdWindow;
lcdWindow.addButton(&myButton, 1, 1);
lcdWindow.draw();
while (1){}
return 0;
}
There are different ways to do this. In principle, you should define an interface (API) to your low-level LCD driver module(s) and call only functions of your low level api to draw something. The implementations of this api can then exchanged without the need to change the high level code.
The simplest way to do this is to define an abstract c++ base class where all lcd driver implementations have to be derived from. The base class should have virtual methods that need to be overloaded by the derived implementations.
But a litte information: virtual methods in c++ classes requires the compiler to generate a method pointer table for every object that is created when the object is instantiated; this needs some more memory. Also, all function calls to objects of these classes are indirect (the compiler generates code that first lookup the real function pointer and then calls the function using this pointer), which makes the resulting code slightly slower.

Refactoring code for drawing game components

How can I refractor the following, to move my drawing functions from the h-file into a GraphicsManager class?
//drawingFunctions.h
void drawTexturedQuad( Texture texture, Vector2 pos, Vector2 dim) {
// bind texture...
glBegin(...); // draw
//...
glEnd(...);
}
//class file
#include "drawingFunctions.h"
class Player {
void drawPlayer(){ drawTexturedQuad( texture, pos, dim) }
};
class Enemy {
void drawEnemy(){ drawTexturedQuad( texture, pos, dim) }
};
class Item {
void drawItem(){ drawTexturedQuad( texture, pos, dim) }
};
// and so on for the other components
//gameloop file
// instantiate components objects
while (true) {
// input, logic
Player.drawPlayer();
Enemy.drawEnemy();
Item.drawItem();
// and so on
}
(The code is obviously simplified, I am just asking about the drawing here)
Should I...
pass a pointer to the GraphicsManager to every call of drawPlayer, drawEnemy etc from within the gameloop
have Player, Enemy etc have a pointer to GraphicsManger as a data member
have Player, Enemy etc extend a drawableGameComponent class that has a pointer to GraphicsManager as a data member
something else?
That sounds like a perfect use case for inheritance:
class Drawable
{
public:
void draw()
{
// gl stuff
}
protected:
Texture _texture;
Vector2 _pos;
Vector2 _dim;
};
class Player : Drawable
{
public:
// should modify _texture _pos and _dim somewhere.
};
// same thing for the other objects.
I would pass a renderer to the model, and ask it to draw itself.
class Player
{
public:
void draw(Renderer& renderer);
};
class Enemy
{
public:
void draw(Renderer& renderer);
};
Note you don't have to name the function drawPlayer or drawEnemy, because you already know that it's a Player or an Enemy by the class type. This uniform calling convention is perfect for extracting into a common interface:
class Model
{
public:
virtual void draw(Renderer& renderer) = 0;
virtual ~Model() {}
};
Then you can have each of your models inherit from Model, and each implement draw.
As I mentioned in a comment on #J.N.'s answer you can also have Renderer be an abstract class. For example I worked on a project which used OpenGL, GDI+, and also needed to create printouts of schematics.
class Renderer
{
public:
virtual render(const Triangle& triangle, const Texture& texture) = 0;
virtual ~Renderer() {}
};
I would go for the first possibility: passing the pointer to the GraphicsManager in the call. Eventhough it seems a bit overkill, the knowledge of which GraphicsManager is used is maintained on higher level and can be modified easier later on.
Having said this, I would still inherit from a Drawable interface and put the items that need to be drawn in a container, so you can just iterate through it to display the items via a virtual drawItem() function.
Like so (C++03, not tested):
std::vector<Drawable*> Items;
Items.push_back(&player);
Items.push_back(&enemy);
...
for (std::vector<Drawable*>::iterator it = Items.begin(); it != Items.end(): ++it)
{
(*it)->drawItem(&graphMgr);
}