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

Author Topic: Aggregating Drawable and Transformable for Polymorphic behavior  (Read 6128 times)

0 Members and 1 Guest are viewing this topic.

broncoAbierto

  • Newbie
  • *
  • Posts: 3
    • View Profile
I am writing an engine for a 2D platformer based on an entity-component-system approach using SFML. Until now, I had a Graphics component with a pointer to sf::Sprite. This sf::Sprite would get drawn by the Rendering System on each update.

Recently I realized that I might want to draw other kinds of elements (Shapes and Text) during gameplay, ideally without changing the Rendering System. So, instead of a pointer to sf::Sprite, I decided that the Graphics component should have a pointer to sf::Drawable. The problem is that in order to draw these elements in the right location I need to invoke their setPosition() method. This is not possible polymorphically because that method belongs to class Transformable.

This could be easily solved. We could have a new class, say Node, that inherits from Drawable and Transformable and stands above Shape, Sprite and Text on the hierarchy.

class Node : public Drawable, public Transformable {

}
 

Instead of inheriting from Drawable and Transformable, classes Shape, Sprite and Text would then inherit from Node.

class SFML_GRAPHICS_API Shape : public Node{
//...

class SFML_GRAPHICS_API Sprite : public Node{
//...

class SFML_GRAPHICS_API Text : public Node{
//...

 

This way, the Graphics component can hold a pointer to sf::Node, which can behave polymorphically as a Shape, a Sprite or Text, exposing the properties that they have in common as subclasses of Drawable and Transformable.

Of course, the drawback is that I have to modify the code of SFML itself. I've tested it and so far I've found no problems, but you can never be sure...

So the questions are:
  • Do you think this is a good solution?
  • Could this change to the source code bring problems that are not evident at first sight?
  • Would this be a good addition to the SFML Graphics architecture?

Edit: I just saw that a very similar proposal was posted here: http://en.sfml-dev.org/forums/index.php?topic=14157.msg99316#msg99316
What eXpl0it3r proposes might be a good alternative, although it could take gymnastics to implement cleanly in an entity-component framework.
« Last Edit: May 26, 2014, 06:57:16 pm by broncoAbierto »

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #1 on: May 26, 2014, 07:09:46 pm »
You could have something similar without inheritance and at the same time being more generic:

struct Node
{
    sf::Drawable& drawable;
    sf::Transformable& transformable;
};
// or with (smart) pointers
 

Where the attributes could refer to the same object.
So you can put sf::Shape, sf::Text, sf::Sprite in it, but also custom drawable that are not transformable (coupled with a dummy Transformable in that case).
SFML / OS X developer

broncoAbierto

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #2 on: May 26, 2014, 07:21:01 pm »
Thanks for the suggestion, Hiura. I think I'm going to end up doing something along that line. Using some of the features offered by C++ for type definition I think I can hide the fact that it's a wrapper rather than a parent class.

If I come up with something decent I'll share it here.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #3 on: May 26, 2014, 07:23:23 pm »
If you go even further, chances are that you need a better level of abstraction, because your requirements go beyond the Drawable/Transformable API; for example: you may need an update() method, or a hierarchical scene graph with parent/children relationship. So in your final design it is very unlikely that this new SFML class is enough to cover your needs. You'll need your own entity system, and sf::Sprite, sf::Text, sf::Shape, sf::VertexArray will just be used as building blocks to implement the most basic nodes of this system. SFML is not meant to be a framework on which you should base your design, it's just a tool box.
Laurent Gomila - SFML developer

broncoAbierto

  • Newbie
  • *
  • Posts: 3
    • View Profile
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #4 on: May 26, 2014, 07:42:30 pm »
Yes, absolutely, I'm gonna need to add a new layer of abstraction, but given the nature of the ECS (Entity-Component-System) approach, this will be a rather unconventional layer.

This class will be part of the Graphics component. I an ECS framework, it's wise to keep components as close to being POD (plain old data) as possible. Certainly, I am going to need to implement inner methods that manage the duality of the Drawable/Transformable object inside the component, but all of this should be invisible to the rest of the engine.

That is, I should be able to do both
sf::Sprite s; graphicsComponent.node = &s;
and
sf::Shape s; graphicsComponent.node = &s;

Calls like
graphicsComponent.node.setPosition(x,y) = &s;
might be unavoidable, but I can live with that.

An update method won't be necessary, for all of the logic is managed elsewhere.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #5 on: May 26, 2014, 08:39:52 pm »
As Laurent said, in the end you might just want to write your own classes that represent text or a simple sprite, as such you'd be able to have your own abstract base class. ;)

Besides that, from a code design standpoint it might be even better to have your own abstraction, because you might not want to have the whole SFML interface exposed, e.g. you want all texts to have a specific font and not let anything else change the font, thus having setFont exposed kind of contradicts that.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Lolilolight

  • Hero Member
  • *****
  • Posts: 1232
    • View Profile
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #6 on: May 28, 2014, 06:27:29 pm »
Why don't you make an abstract class and don't you draw graphical objects of this abstract class on components ???

Personnaly this is what I do and it works very well.

Hydrogen

  • Newbie
  • *
  • Posts: 3
    • View Profile
    • Email
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #7 on: February 25, 2017, 01:35:41 am »
This is a very old thread, but I wanted to second the suggestion of actually making this change to the inheritance hierarchy. Looking at the documentation, I notice that (a) the classes that inherit from both Drawable and Transformable are exactly Shape, Sprite, and Text, and (b) Shape, Sprite, and Text each inherit exclusively from Drawable and Transformable. Thus it seems clear to me that "Drawable and Transformable" semantically describes a third type, which is conspicuously missing from the hierarchy.

Yes, there are workarounds, and no, this change won't solve every problem, but I still think it would be useful for many common cases, with no tangible drawbacks.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Aggregating Drawable and Transformable for Polymorphic behavior
« Reply #8 on: February 25, 2017, 09:13:47 am »
Maybe we can find a single base for those types, but it wouldn't be a merge of sf::Drawable and sf::Transformable, it would probably be a third class or a redesign of the whole thing. These two classes have nothing in common, so there's no reason to merge them (keeping separate features in separate classes is important in my opinion). I'm even sure that it is not uncommon to see one or the other used alone in user code.

And don't forget that sf::Transformable is not abstract and can be used alone directly.
Laurent Gomila - SFML developer