Category Archives: c++

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:
gameobject.h

#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
{
public:
    c_gameobject(); 
   ~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*> 
    t_component_list;
	
    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;

protected:
	
private:
    // 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: jspataro@gmail.com
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;
		
        m_component_list.push_back(new_component);

        // 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));
            break;
        }		
    }

    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;
            break;
        }
    }

    return result;
}

and gameobject.cpp

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

c_gameobject::c_gameobject() 
{
    // game objects are just a unique identifier
    // and a transform
    CoCreateGuid(&m_guid);	

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

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

        if (++component_iterator == m_component_list.end())
        {
            m_component_list.clear();
        }
    }
}

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)
    {
        (*component_iterator)->update(dt);		
    }
}

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
use.


// 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
{
...

public:
    // 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!

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
{
    _item_flags_single_use,	
    _item_flags_placed_in_world,
    _item_flags_can_be_traded,
    _item_flags_causes_effect_on_use,
    _item_flags_can_respawn,
    k_item_flags_count
};

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
{
public:
    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 );

private:
    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 )
{
    clear();
}

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 )
{
    bitvector.clear_all();
}

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