1
\$\begingroup\$

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.

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.

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.

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

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:

Game Entity class:

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<typename T>
void send(Component::Command command,T value){
       //Iterates through the vector, calling the receive method for each component
    for(std::vector<Component*>::iterator it =components.begin();  it!=components.end();it++){
        (*it)->receive(command,value);
    }
}
private:
     vector <Component*> components;    

};

Component Class:

#include "GameEntity.h"
class Component
{
public:
static enum Command{STEP_TIME, TOGGLE_ANTI_ALIAS, REPLACE_SPRITE};

Component(GameEntity* parent)
    {this->compParent=parent;};

virtual ~Component (void){};    

GameEntity* parent(){
    return compParent;
}
void setParent(GameEntity* parent){
    this->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;

};

A possible extension of the Component class:

#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->sprite=value; break
                 }
           }

    private:
          Spite sprite;


}

Should I use a void 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.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

If you have two components that need to talk to each other, hiding the types or not letting them communicate to each other directly isn't really going to do anything other than hide the coupling that already exists.

I'd get rid of the generic "receive" method and instead just make it so you can get a component by type and call methods on it directly. Unity does this with its GetComponent<T> method, which in your case might look something like this (untested, and using C++11 for loops for brevity):

template< typename T >
T* GetComponent<T>() {
    for( auto component : components )
    {
        T componentAsT = dynamic_cast<T>( component );
        if( componentAsT != null ) 
            return componentAsT;
    }
    return null;
 }
\$\endgroup\$
3
  • \$\begingroup\$ Please see gamedev.stackexchange.com/questions/35061/… for an example of why I choose to implement my class in this manner. \$\endgroup\$
    – RabtFt
    Apr 10, 2013 at 18:26
  • \$\begingroup\$ "...hide the coupling that already exists..." I think it is about how loose your coupling needs to be rather then about complete presence or absence of it. Mediators/observers were invented for a reason. I personally would at least make sure those T-s are interfaces not concrete classes. \$\endgroup\$
    – Den
    Apr 10, 2013 at 20:52
  • \$\begingroup\$ Events and observers are one thing, hiding function calling through messages, switch statements on enums, and so on is something else. You won't find me necessarily arguing against interfaces, but you will find me arguing against premature generalization. \$\endgroup\$
    – Tetrad
    Apr 10, 2013 at 22:55

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .