Still typing

Published April 11, 2010
Advertisement
General stuff
Ah it's good to be back home in GameDev City. Been out in the wilds for too long and now my bones ache. Really, for a month or so it's been quite intense at school and all past time activities (like game dev, eating peas, etc.) have been on hold. Specifically I've been doing a lot of programming for assignments so whenever I got some time off, more coding was the last thing I wanted to do. It's been been good though. I'm closing in on my M.Sc. degree. Soon I will be free. ^_^

Have been playing games instead, catching up a bit on all the titles I've missed so far. Since new-year I've plowed through inFamous, Brutal Legend, God of War I and II, all awesome experiences. Well I didn't really get my head around the Brutal Legend gameplay but then again that is not what you look for in a Schafer game. inFamous was probably the best city-roaming action game I've played to date and the God of War titles are just awesome. They give a new angle to the concept of "spartan decoration" of a room; a lot more blood and dead bodies.

Citizen stuff
Now, yesterday I finally got back to coding on Citizen, mainly by doing some refactoring. I realized I could smooth out the interface of the EntityManager class by using some member function templates for the component factories. Up until now every component type have had it's own custom factory function in EntityManager. This was a thorn in my side; I've wanted to generalize this as the factory implementations look the same apart from the component type.

The problem was to make EntityManager aware of which component type it creates so that it can pass it on to the correct manager. The component managers were members of EntityManager; they could be distinguished at run-time, but to use a templated factory they needed to be distinguishable at compile-time. The solution I found was instead to let EntityManager privately inherit all the component managers. By making the component manager classes specialized implementations of a ComponentManager template the factory template in EntityManager could can cast the this pointer to a component manager pointer using the template parameter, thereby getting access to the correct component manager at compile-time.

Confusing, yes? Don't worry, I'll try to illustrate it with an example.

Previous version
// Assume there exists a number of component types:// FirstComp, SecondComp, ThirdComp...// The component manager base class keeps core functions like// managing the list of components of a certain type.class ComponentManagerBase {public:    // This is the actual factory that EntityManager should relay to.    void createComponent( ... );};// The component manager classes all inherit the base manager.// Then they each add their own specific functionality.class FirstCompManager : public ComponentManagerBase { ... };class SecondCompManager : public ComponentManagerBase { ... };class ThirdCompManager : public ComponentManagerBase { ... };class EntityManager {private:    // Each manager is instanced to manage components of only that type.    FirstCompManager firstCompMan;    SecondCompManager secondCompMan;    ThirdCompManager thirdCompMan;public:    // Each manager factory call must be implemented separately.    void createFirstComp( ... ) {        ... // Do entity stuff        firstCompMan.createComponent( ... );    }    void createSecondComp( ... ) {        ... // Do entity stuff        secondCompMan.createComponent( ... );    }    void createThirdComp( ... ) {        ... // Do entity stuff        thirdCompMan.createComponent( ... );    }};

Current version
// Assume there exists a number of component types:// FirstComp, SecondComp, ThirdComp...// A dummy template for the managers. All implementations are actually specialized.template class ComponentManager;// The component manager base class keeps core functions like// managing the list of components of a certain type.class ComponentManagerBase {public:    // This is the actual factory that EntityManager should relay to.    void createComponent( ... );};// The component manager classes all inherit the base manager.// Then they each add their own specific functionality.template<> class ComponentManager : public ComponentManagerBase { ... };template<> class ComponentManager : public ComponentManagerBase { ... };template<> class ComponentManager : public ComponentManagerBase { ... };class EntityManager :    // Note: private inheritance.    private ComponentManager,    private ComponentManager,    private ComponentManager{public:    // Template for component factories.    template    void createComponent( ... ) {        // Cast yourself into a component manager aspect based on type parameter        // and call the factory function on that aspect.        ... // Do entity stuff        ((ComponentManager*)this)->createComponent( ... );    }};

The key thing to realize here is that in the current version EntityManager is a component manager of each type so it can be cast to that type to access the members that otherwise would hide each other. Since the inheritance is private, the component manager aspects are invisible to the outside observer, making it appear as a basic class as before.

Note that this code is simplified for clarity. For example, the real ComponentManagerBase is also templated on CompType because it keeps a collection of objects of that specific type.

Conceptually, in the previous version, we have a straight inheritance tree from the managers to the manager base and an instance of each derived manager type in EntityManager. In the current version on the other hand we have what seems like a diamond setup, but isn't, because each component manager class derives from a different specialization of ComponentManagerBase<> which is a unique type.

All in all this change shortens the code and allows for much easier addition of new component types in the future. I begin to find myself more comfortable using templates in various situations. Good times.
Previous Entry Dark days
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement