Tu as une mauvaise approche. Il ne faut pas chercher à bâtir tout ton système avec les classes SFML, SFML n'est pas un moteur ou un framework. Il faut que tu conçoives tes propres classes de base, adaptées au système que tu veux mettre en place, puis ensuite tu remplis les implémentations correspondantes avec des sf::Sprite, sf::Shape ou autre. En gros, ce ne sont pas des sprites ou des shapes que tu mets dans ton scenegraph, mais plutôt des noeuds capables de dessiner des sprites et des shapes.
Typiquement tu auras ça (pseudo-code):
class Node : public sf::Drawable, public sf::Transformable
{
void draw(target, states)
{
states.transform *= getTransform();
drawSelf(target, states);
foreach (child node)
target.draw(child, states);
}
virtual void drawSelf(target, states) = 0;
};
class SpriteNode : public Node
{
...
virtual void drawSelf(target, states)
{
target.draw(m_sprite, states);
}
sf::Sprite m_sprite;
}
C'est pas ça que tu cherches ?
type erasure
(fait de tête, j'ai peut-être fait une erreur mais en gros c'est ça)
/* objet générique */
class AbstractNode
{
public:
AbstractNode();
virtual ~AbstractNode();
virtual void mySexyMethod() = 0;
...
// (et toutes celles qu'on veut public)
};
/* objet conteneur */
template<class Object>
class Node : public AbstractNode
{
public:
Node(Object& o);
virtual ~Node();
virtual void mySexyMethod() override;
...
private:
Object& m_object;
};
template<class Object>
Node<Object>::Node(Object& object) :
m_object(object)
{}
template<class Object>
Node<Object>::mySexyMethod()
{
m_object.mySexyMethod();
}
/* création */
AbstractNode prout = Node(*new Sprite);
prout.mySexyMethod();
En fait je crois qu'on dis la même chose depuis le début, ce n'est qu'une légère différence de vocabulaire qui donne l'impression qu'on est pas d'accord.
class AbstactNode
: public sf::Drawable, public sf::Transformable
{
};
class SpriteNode
: public AbstractNode
{
private:
sf::Sprite mSprite;
public:
// Un get/set sur le sprite
sf::Sprite& getSprite() { return mSprite; }
void setSprite(const sf::Sprite& s) { mSprite = s; }
// Ré-implémentation de sf::Transformable
void setPosition(float x, float y) { mSprite.setPosition(x, y); }
void setPosition(const sf::Vector2f& p) { mSprite.setPosition(p); }
// etc...
};
class RectangleShape
: public AbstractNode
{
private:
sf::RectangleShape mShape;
public:
// Un get/set sur le sprite
sf::RectangleShape& getShape() { return mShape; }
void setShape(const sf::RectangleShape& s) { mShape = s; }
// Ré-implémentation de sf::Transformable
void setPosition(float x, float y) { mShape.setPosition(x, y); }
void setPosition(const sf::Vector2f& p) { mShape.setPosition(p); }
// etc...
};
AbstractNode* n = new SpriteNode();
n.setPosition(24, 73);
// etc...
Si je veux pouvoir faire du polymorphisme afin d'avoir un code capable de manipuler et dessiner les nodes, peut importe le type réel qu'il y a derrière, je suis bel et bien obligé d'implémenter sf::Transformable et sf::Drawable.
Si je me contente du get/set, alors je ne peux pas faire de .setPosition() sur mon node. Je suis obligé de savoir qu'il s'agit d'un SpriteNode pour faire un .getSprite().setPosition().
Pour autant, comme je disais plus haut, écrire un "proxy" me procure toujours un petit sentiment de gène, j'ai l'impression de faire un truc que je ne devrais pas.
C'est pour ça que, dans la mesure où tu as les Sprites et les Shapes qui héritent déjà de Transformable ET de Drawable, je ne comprend pas quelles sont les raisons qui font qu'il n'y a pas un héritage intermédiaire qui donnerai un parent unique à toute ces classes. Ce qui permettrait d'utiliser cette classe comme base pour le polymorphisme, sans pour autant m'en servir comme un framework ou un moteur.
Je ne compte pas dériver Sprite pour en faire un personnage par exemple.
En supposant que :
namespace sf
{
class Transformable { /* ... */ };
class Drawable { /* ... */ };
class DisplayableObject : public Transformable, public Drawable { /* ... */ };
class Sprite : public DisplayableObject { /* ... */ }:
class Shape : public DisplayableObject { /* ... */ };
}
J'aurai alors pondu un code de ce genre là :
class Node
{
// Tout ce qu'il faut pour gérer un arbre, un pointeur sur le parent, une liste d'enfant, etc...
};
class AbstractEntity
: public Node
{
virtual sf::DisplayableObject& getObject() = 0;
};
class CharacterEntity
{
private:
sf::Sprite mSprite;
public:
virtual sf::DisplayableObject& getObject() { return mSprite; }
};
void MoveAndDraw(AbstractEntity* entity, sf::RenderTarget& target)
{
entity->getObject().setPosition(27, 93);
target.draw(entity.getObject());
}