Note that there are some explanatory texts on larger screens.

plurals
  1. POFlexible Data Messaging in a component oriented system
    primarykey
    data
    text
    <p>I'm creating a Component orientated system for a small game I'm developing. The basic structure is as follows: Every object in the game is composed of a "GameEntity"; a container holding a vector of pointers to items in the "Component" class. </p> <p>Components and entities communicate with one another by calling the send method in a component's parent GameEntity class. The send method is a template which has two parameters, a Command (which is an enum which includes instructions such as STEP_TIME and the like), and a data parameter of generic type 'T'. The send function loops through the Component* vector and calls each's component's receive message, which due to the template use conveniently calls the overloaded receive method which corresponds to data type T.</p> <p>Where the problem comes in however (or rather the inconvenience), is that the Component class is a pure virtual function and will always be extended. Because of the practical limitation of not allowing template functions to be virtualised, I would have to declare a virtual receive function in the header for each and every data type which could conceivably be used by a component. This is not very flexible nor extensible, and moreover at least to me seems to be a violation of the OO programming ethos of not duplicating code unnecessarily. <br><br> <strong>So my question is, how can I modify the code stubs provided below to make my component orientated object structure as flexible as possible without using a method which violates best coding practises</strong></p> <p>Here is the pertinent header stubs of each class and an example of in what ways an extended component class might be used, to provide some context for my problem:</p> <p>Game Entity class:</p> <pre><code>class Component; class GameEntity { public: GameEntity(string entityName, int entityID, int layer); ~GameEntity(void){}; //Adds a pointer to a component to the components vector. void addComponent (Component* component); void removeComponent(Component*); //A template to allow values of any type to be passed to components template&lt;typename T&gt; void send(Component::Command command,T value){ //Iterates through the vector, calling the receive method for each component for(std::vector&lt;Component*&gt;::iterator it =components.begin(); it!=components.end();it++){ (*it)-&gt;receive(command,value); } } private: vector &lt;Component*&gt; components; }; </code></pre> <p>Component Class: #include "GameEntity.h" class Component</p> <pre><code>{ public: static enum Command{STEP_TIME, TOGGLE_ANTI_ALIAS, REPLACE_SPRITE}; Component(GameEntity* parent) {this-&gt;compParent=parent;}; virtual ~Component (void){}; GameEntity* parent(){ return compParent; } void setParent(GameEntity* parent){ this-&gt;compParent=parent; } virtual void receive(Command command,int value)=0; virtual void receive(Command command,string value)=0; virtual void receive(Command command,double value)=0; virtual void receive(Command command,Sprite value)=0; //ETC. For each and every data type private: GameEntity* compParent; }; </code></pre> <p>A possible extension of the Component class:</p> <pre><code>#include "Sprite.h" #include "Component.h" class GraphicsComponent: Component{ public: GraphicsComponent(Sprite sprite, string name, GameEntity* parent); virtual void receive(Command command, Sprite value){ switch(command){ case REPLACE_SPRITE: this-&gt;sprite=value; break } } private: Spite sprite; } </code></pre> <p>Should I use a null pointer and cast it as the appropriate type? This might be feasible as in most cases the type will be known from the command, but again is not very flexible.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload