Simple game object / component system : part 1

In the engine I’m coding, I got to the part where I needed to write what is commonly called the game object system or game object model. Typically in games, there are a variety of object types; rocket launchers, giant orcs, starving pelicans, and of course, crates. The game object model provides an architecture by which all of these objects can be created, destroyed, updated, looked up, and so on.

Before I got started, I clicked through some old gdc slide decks, and thumbed through some of the books in my technical library. What I found was that there were quite a few ways to go when it comes to game object models, but there were two prevalent models: a game object was either started as an abstract base class that was sub-classed and extended to make a concrete object type, or was a simple object that wasn’t sub-classed at all, and concrete object types were built out of a variety of component classes that each represented different behavior.

After shipping a few games, I have been exposed to a couple different game object models, but nothing that departs from either of the paradigms mentioned above. Ultimately though, for my own engine I wanted to replicate some aspects of the way Unity3D works. The workflow in the editor is so streamlined and it really is easy to get things up and running.

The features I wanted in my game object model were:

  • Data declaration through script
    • Similar to Torque3D’s datablocks
    • A template or blueprint for an object’s component list, which gets instanced
    • Instances are placed in a map editor
    • The template gets sent across the network only once
  • Both scripted and native c++ components
  • Messages sent/received/handled in script or native code
  • Game object itself is very lightweight, maybe just a guid and a transform
    • Game objects can be extended in script with key/value pairs of properties

Once I started the work, I thought it would be a good opportunity for a series of posts.

Let’s start with the code that defines a game object:

#pragma once

#include <ObjBase.h> // GUID
#include "eastl/list.h"

class c_component;
class c_transform_component;

// A game object is an object that can be placed in our game world
// each created game object has a unique identifier
// game objects can have components attached to themselves.
// by default, all game objects have a transform component attached
// the transform is the only component the gameobject 'knows' about.
class c_gameobject

    // game objects get updated every tick
    // inside our game object update we will give attached components
    // a chance to update.
    void update(double dt);

    // game objects expose a templated add_component method so that 
    // our game object doesn't need to know what kind of components 
    // exist.
    template <class t_component> 
    t_component* add_component();

    // our get_component method is also templated, again so that 
    // our game object doesn't need to know what kind of components
    // exist
    template <class t_component> 
    t_component* get_component();	
    // internally, our game object will keep a list of the components
    // that are attached.  You can use any flavor of list.
    // I recently switched from rolling my own generic containers to
    // using eastl.  
    typedef eastl::list<c_component*> 
    const t_component_list* get_components() const 
        return &m_component_list;
    // all game objects in our world need to be uniquely identifiable
    // for this purpose, I am using a guid.  You can use any mechanism
    // that guarantees the game object will be unique.
    inline GUID get_guid() const 
        return m_guid;
    // here are a couple of operators used for comparing one game object
    // against another for equality.
    bool operator ==(const c_gameobject& rhs) const;
    bool operator !=(const c_gameobject& rhs) const;

    // this could pobably be public, but using get_component
    // calls this anyways, so it would be redundant for users to
    // ask has_component and then call get_component
    // therefore get_component just returns NULL if the component
    // type in question is not attached.
    template <class t_component> 
    bool has_component();

    GUID m_guid;
    t_component_list m_component_list;

    // we need not necessarily store this, but it's more efficient
    // speed wise to just access it this way rather than calling
    // get_component internally, and even if we were doing it that way
    // we would be asking for a c_transform_component then, so it's
    // better to just store it imo.	
    c_transform_component* m_transform;

// our templated methods need to go inside the .h file.

// in c# you can do stuff like class MyClass<T> where T : SomeClass
// I would love to know how I can ensure that t_component is derived
// from c_component
// if anyone knows how to do that, shoot me an email:
template <class t_component>
t_component* c_gameobject::add_component()
    // interesting.
    // I didn't want all the overhead of a singleton for this
    // what this is, is a place where components register themselves
    // as a unique id (guid) and a creation function pointer
    // the creation function just needs to return a pointer to the
    // new component
    // so the component registry is just a hash table where guids
    // map to creator functions.
    extern t_component_registry g_component_registry;

    // for now, only one of any type of component can be attached
    // to a game object. Later on when we add scripted components
    // we'll allow more than one of those to be attached.
    // this is meant to prevent two transforms/renderers, etc.
    // from being attached because what would that mean aynways?
    // And, what would be the best way to resolve that abiguity?
    t_component* found_component= get_component<t_component>();

    if (found_component)
        // so we already had a component of this type attached
        // just return it.
        return found_component;

    // get the creator function from our hash table using the component's
    // guid as the key.
    // you can use whatever flavor of hashtable or map you prefer.
    const component_creator* creator= g_component_registry.get_value(t_component::type());

    // we don't know what kind of component we are creating until 
    // later, so our creator functions actually give back a pointer
    // which is cast to a c_component (the superclass of all components)
    c_component* new_component = NULL;

    // I'm not checking this against validity because internally, my hashtable
    // will barf if asked for a key that doesn't exist.
    new_component= (*creator)();

    // actually creating the component, however, could fail
    // if we were out of memory, for example...	
    if (new_component)
        // components know which game object they are attached to
        new_component->gameobject= this;

        // finally, we want to give back the pointer cast to the
        // actual component type we are creating/attaching.
        return static_cast<t_component*>(new_component);

    return NULL;

// walk the list of components
// check their type against the type we are looking for
// return a pointer to the component if found
// otherwise, return NULL
template <class t_component>
t_component* c_gameobject::get_component()
    t_component *result= NULL;	
    eastl::list<c_component*>::iterator component_iterator= m_component_list.begin();

    for ( ; component_iterator != m_component_list.end(); ++component_iterator)
        // the eastl list is holding pointers to components, so the first check
        // where we dereferece the iterator is actually checking to see if the 
        // pointer to the component is not NULL
        if ((*component_iterator) && (*component_iterator)->get_instance_type() == t_component::type())
            // we always cast to the pointer type we're looking for
            result= static_cast<t_component*>((*component_iterator));

    return result;

// walk the component list
// check their type against the type we are looking for
// return true if found, otherwise false
template <class t_component>
bool c_gameobject::has_component()
    bool result= false;

    eastl::list<c_component*>::iterator component_iterator= m_component_list.begin();

    for ( ; component_iterator != m_component_list.end(); ++component_iterator)
        if ((*component_iterator) && (*component_iterator)->get_instance_type() == t_component::type())
            result= true;

    return result;

and gameobject.cpp

#include "gameobject.h"
#include "component.h"
#include "transform.h"

    // game objects are just a unique identifier
    // and a transform

    // all game objects have at least a transform.
    m_transform= add_component<c_transform_component>();

// iterate over each component and call its destruct method
    eastl::list<c_component*>::iterator component_iterator= m_component_list.begin();
    while (!m_component_list.empty())
        if ((*component_iterator))

        if (++component_iterator == m_component_list.end())

bool c_gameobject::operator ==(const c_gameobject& rhs) const 
    // which one of these is the right way?

    // this one uses memcmp, AND, if I want to return a bool, 
    // this gets converted from an int...which isn't super efficient
    //return (guid == rhs.get_guid());

    // I not certain that any object's data1 values would ever be 
    // identical if they were different objects...
    return (m_guid.Data1 == rhs.get_guid().Data1);

bool c_gameobject::operator !=(const c_gameobject& rhs) const
    return (m_guid.Data1 != rhs.get_guid().Data1);

void c_gameobject::update(double dt)
    eastl::list<c_component*>::iterator component_iterator= m_component_list.begin();

    for ( ; component_iterator != m_component_list.end(); ++component_iterator)

In the next part, we’ll tackle components

template template parameters example

In this example you’ll learn how to use template template parameters. ¬†We’ll use the template template parameter to specify the memory allocation policy of some imaginary ‘manager’ class that games often have.

We’ll pretend that we have some kind of texture manager that is responsible for the life of a texture class. We’ll be using a template parameter to specify which allocation policy the manager will

// The only requirement for our memory allocation policy is to have a static 
// function that returns a pointer to the type we are creating. Each policy
// should have an identically named function. Here we are calling ours 
// 'construct'.
template <class t_constructed>
struct s_allocation_policy_operator_new
    // this "constructor" takes no parameters,
    // but we could also make versions that do...
    static t_constructed* construct()
        return new t_constructed;

// here is another allocation policy using malloc
template <class t_constructed>
struct s_allocation_policy_malloc
    static t_constructed* construct()
        return (t_constructed*)malloc(sizeof(t_constructed));        

// now for the fun part:
// here we are going to do a couple of interesting things, first note how we
// inherit our manager class from a template parameter. Interesting!
// This is how we can later specify which allocation policy to use.
template <template <class t_constructed> class t_allocation_policy>
class c_texture_manager : public t_allocation_policy

    // here the c_texture isn't a template parameter because we are
    // pretending that our manager always manages c_texture objects.
    // but c_texture could easily be an abstract base class for all of
    // the various types of textures
    // you might think that t_constructed is meant to fill this role within
    // the definition of c_texture_manager, but actually t_constructed here isn't
    // a part of c_texture_manager's definition at all and could be omitted, but
    // it IS a parameter to t_allocation_policy.
    c_texture* create_texture();


// and here is the implementation of create_texture.
// you can see how c_texture fills in the template parameter t_constructed
// for t_creation_policy
template <template <class t_constructed> class t_creation_policy>
c_texture* c_texture_manager<t_creation_policy>::create_texture()
    // here we call the allocation policy's static construct function.
    return t_creation_policy<c_texture>::construct();

// finally, here's how the client code would look.
// this texture manager uses the new operator.
typedef c_texture_manager<s_allocation_policy_operator_new> t_texture_manager;

// or, we could specify a different allocation policy.
// this one would use malloc
typedef c_texture_manager<s_allocation_policy_malloc> t_texture_manager;


extern t_texture_manager g_texture_manager;


c_texture* new_texture= g_texture_manager.create_texture();

Perhaps when you start your game project you haven’t yet written your memory manager and you start off using a policy that allocates objects using the global new operator, with this pattern we can easily later switch out new and use a custom memory manager.

have fun!

bidirectional script <-> maya transform in python

I thought it might be interesting to have a two-way connection between an object in maya and script. What do I mean by this? Well, imagine that you create a transform, joint, or locator in script and update some of its attributes, and naturally, the change is reflected in the 3d view; but then you drag the object around in the 3d view, and now the changes are reflected in the instance in script.

Here is an example of the usage:

transform= c_transform(name= "test_transform", translate= [1.0,0.0,0.0])
# change the rotation
transform.rx= 90.0 

# now grab the transform and translate or rotate it.

# then check the translation or rotations

# you can also access by attr
transform.tx= 5.0

Here is the actual code for this. Note that the transform can be parented under another object and its attributes will be correctly updated. With all of the callbacks for attrs changing and parenting and such, as well as the branchy/fugly attr checking, this code is really slow so I wouldn’t recommend using this to create tons of objects. This was mostly on a whim anyhow, and not for real production.

import maya.cmds as cmds
import maya.OpenMaya as om
import math

class c_transform(object):
    name= None
    translate= []
    rotate= []
    scale= []
    set_from_script= False  
    on_attr_changed_id= None
    on_node_destroyed_id= None
    on_parent_added_callback_id= None
    on_name_changed_callback_id= None
    def __init__(self, *args, **kwargs):
        self.set_from_script= True
        self.tx= 0
        self.ty= 0 0

        self.translate= [self.tx,self.ty,]

        self.rx= 0
        self.ry= 0
        self.rz= 0

        self.rotate= [self.rx,self.ry,self.rz] 1 1 1

        self.scale= [,,]


        self.create(*args, **kwargs)

        if kwargs.has_key('translate') and type(kwargs['translate']) is list:
            self.tx= kwargs['translate'][0]
            self.ty= kwargs['translate'][1]
            self.translate= [self.tx, self.ty,]
            cmds.setAttr('.translateX', self.tx)
            cmds.setAttr('.translateY', self.ty)

        if kwargs.has_key('rotate') and type(kwargs['rotate']) is list:
            self.rx= kwargs['rotate'][0]
            self.ry= kwargs['rotate'][1]
            self.rz= kwargs['rotate'][2]
            self.rotate= [self.rx, self.ry, self.rz]
            cmds.setAttr('.rotateX', self.rx)
            cmds.setAttr('.rotateY', self.ry)
            cmds.setAttr('.rotateZ', self.rz)

        if kwargs.has_key('scale') and type(kwargs['scale']) is list:
            self.scale= [,,]
        dag_iter= om.MItDag()
        found= False        
        while not dag_iter.isDone() and found == False:
            curr= dag_iter.currentItem()
            fn= om.MFnDependencyNode(curr)
            if ==              
                self.on_attr_changed_id = om.MNodeMessage.addAttributeChangedCallback(curr, self.on_attr_changed)
                self.on_node_destroyed_id= om.MNodeMessage.addNodeDestroyedCallback(curr, self.on_node_destroyed)
                self.on_name_changed_callback_id= om.MNodeMessage.addNameChangedCallback(curr, self.on_name_changed)
                dag_path= om.MDagPath()
                om.MDagPath.getAPathTo(curr, dag_path)
                self.on_parent_added_callback_id= om.MDagMessage.addParentAddedDagPathCallback(dag_path, self.on_parent_added)
                found= True
    def create(self, *args, **kwargs):
        if kwargs.has_key('name'):          
   cmds.createNode('transform', n=kwargs['name'])
        elif kwargs.has_key('n'):
   cmds.createNode('transform', n=kwargs['n'])
    def __del__(self):
        # print("calling __del__")
    def on_node_destroyed(self, clientData=None):
        print("node destroyed callback")
    def on_name_changed(self, node, old_name, clientData=None):     new_name
    def on_attr_changed(self, msg, plug, other_plug, clientData= None):         
        if msg & om.MNodeMessage.kAttributeSet:         
            if plug.isCompound():
                #print ("Trying to set plug " + plug.partialName())
                for i in range(0,plug.numChildren()):
                    child_plug= plug.child(i)
                    if self.__dict__.has_key(child_plug.partialName()):                 
                        self.set_from_script= False
                        if child_plug.partialName() not in ['rx', 'ry', 'rz']:
                            self.__setattr__(str(child_plug.partialName()), child_plug.asFloat())
                            self.__setattr__(str(child_plug.partialName()), math.degrees(child_plug.asFloat()))
                        self.set_from_script= True                  
                if self.__dict__.has_key(plug.partialName()):
                    #print ("Trying to set plug " + plug.partialName())
                    self.set_from_script= False
                    if plug.partialName() not in ['rx', 'ry', 'rz']:
                        self.__setattr__(str(plug.partialName()), plug.asFloat())
                        self.__setattr__(str(plug.partialName()), math.degrees(plug.asFloat()))
                    self.set_from_script= True
    def on_parent_added(self, child, parent, clientData= None):
        fnc= om.MFnDependencyNode(child.node())
        fnp= om.MFnDependencyNode(parent.node())        
        tx= self.getAttr('tx')
        ty= self.getAttr('ty')
        tz= self.getAttr('tz')
        rx= self.getAttr('rx')
        ry= self.getAttr('ry')
        rz= self.getAttr('rz')
        sx= self.getAttr('sx')
        sy= self.getAttr('sy')
        sz= self.getAttr('sz')
        v=  self.getAttr('v')       
        self.tx= tx
        self.ty= ty tz
        self.rx= rx
        self.ry= ry
        self.rz= rz sx sy sz
        self.v=  v
    def getAttr(self, attr):
        return cmds.getAttr('.'+attr)

    def __setattr__(self, attr, value):
        #print ("calling __setattr__ ", attr, value)
        if attr == 'name':
            if != None:
                if cmds.objExists( and != value:
                    cmds.rename(, value)               
                    self.__dict__['name']= value
                elif cmds.objExists(value) and != value:
                    self.__dict__['name']= value
                self.__dict__['name']= value
        if attr == 'set_from_script':
            self.__dict__[attr]= value
        if attr == 'v':         
            self.__dict__[attr]= value
            self.__dict__['visibility']= self.__dict__['v']
        if attr == 'visibility':
            self.__dict__[attr]= value          
            self.__dict__['v']= self.__dict__['visibility'] 
        if self.__dict__.has_key(attr) and attr != "translate" and attr != "rotate" and attr != "scale":
            if self.__dict__[attr] != value:                
                self.__dict__[attr]= value
                # clamp super small numbers to 0
                if type(value) is float and (value > 0 and value < 0.00001) or (value < 0 and value > -0.00001):
                    value= 0.0
                if type(value) is list:
                    idx= 0
                    for v in value:
                        if type(v) is float and (v > 0 and v < 0.00001) or (v < 0 and v > -0.00001):
                            value[idx]= 0.0
                        idx= idx+1
                if attr == 'tx' or attr == 'ty' or attr == 'tz':
                    if attr == 'tx':                        
                        self.__dict__['translate']= [value, self.ty,]
                    elif attr == 'ty':
                        self.__dict__['translate']= [self.tx, value,]
                    elif attr == 'tz':
                        self.__dict__['translate']= [self.tx, self.ty, value]
                elif attr == 'rx' or attr == 'ry' or attr == 'rz':
                    if attr == 'rx':
                        self.__dict__['rotate']= [value, self.ry, self.rz]
                    elif attr == 'ry':
                        self.__dict__['rotate']= [self.rx, value, self.rz]
                    elif attr == 'rz':
                        self.__dict__['rotate']= [self.rx, self.ry, value]
                elif attr == 'sx' or attr == 'sy' or attr == 'sz':
                    if attr == 'sx':
                        self.__dict__['scale']= [value,,]
                    elif attr == 'sy':
                        self.__dict__['scale']= [, value,]
                    elif attr == 'sz':
                        self.__dict__['scale']= [,, value]                           
        elif attr == "translate" and type(value) is list:
            self.__dict__[attr]= value
            self.__dict__['tx']= value[0]
            self.__dict__['ty']= value[1]
            self.__dict__['tz']= value[2]
        elif attr == "rotate" and type(value) is list:
            self.__dict__[attr]= value
            self.__dict__['rx']= value[0]
            self.__dict__['ry']= value[1]
            self.__dict__['rz']= value[2]
        elif attr == "scale" and type(value) is list:
            self.__dict__[attr]= value
            self.__dict__['sx']= value[0]
            self.__dict__['sy']= value[1]
            self.__dict__['sz']= value[2]
        if self.set_from_script == True:
    def update(self):
        if self.set_from_script == True:
            if != None:           
                cmds.setAttr('.translateX', self.tx)
                cmds.setAttr('.translateY', self.ty)
                cmds.setAttr('.rotateX', self.rx)
                cmds.setAttr('.rotateY', self.ry)
                cmds.setAttr('.rotateZ', self.rz)
                cmds.setAttr('.visibility', self.v)
    def reset(self):
        self.translate= [0,0,0]
        self.rotate= [0,0,0]
        self.scale= [1,1,1]
        self.visibility= True

simple templated bit flags class example

The inaugural post in this category is a fun little example–a simple templated bit flags class.
Sometimes, it is nice to be able to index into a bitvector with an enumeration. Take a look at this example:

// No more than size of 32 bits
enum e_item_flags

typedef c_flags<e_item_flags, k_item_flags_count> c_item_flags; 

c_item_flags item_flags;


item_flags.set( _item_flags_single_use, false );
item_flags.set( _item_flags_placed_in_world, true);
item_flags.set( _item_flags_can_be_traded, true);

if ( item_flags.test(_item_flags_can_be_traded) )
    // code to trade item

Here we have wrapped a bitvector class as a templated flags class with an enum as the template parameter, and then typedef’d it to make it a little more readable. Finally, an example of the actual usage is shown. We are pretending that we have an ‘item’ class in a game, and we have a bunch of flags that specify some properties of the item. In this case, we are going to write the code to handle trading the item, so we’ll need to test the bit specifying whether the item in question can be traded. The whole point of this little example is that we can use the enum we defined to index into the bitvector to set or test bits. Simple and sweet. What does the code for the templated flags class look like? Take a look at the code below (flags.h):

template <typename t_enum, int max_count>
class c_flags
    c_flags<t_enum, max_count>( void );
   ~c_flags<t_enum, max_count>( void );

    void set( t_enum, bool value );
    bool test( t_enum );
    void clear( void );

    c_bitvector32 bitvector;

template <typename t_enum, int max_count>
c_flags<t_enum, max_count>::c_flags( void )
    bitvector.resize( max_count );

template <typename t_enum, int max_count>
c_flags<t_enum, max_count>:: ~c_flags( void )

template<typename t_enum, int max_count>
void c_flags<t_enum, max_count>::set( t_enum T, bool value )
    bitvector.set( T, value );

template<typename t_enum, int max_count>
bool c_flags<t_enum, max_count>::test( t_enum T )
    return bitvector.test( T );

template<typename t_enum, int max_count>
void c_flags<t_enum, max_count>::clear( void )

I’m not going to go over the code for the bitvector itself, but it is pretty simple and I’ve included it at the bottom of this post. One shortcoming is that it only supports 32 bits. This is easily extended, however, so I’ll leave that to you. Furthermore, it would be nice to extend the bitvector to allow serialization (reading/writing to a file.)

example code

game development blog