Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to organize entities in a game?

Tags:

c++

opengl

Let's say I'm creating an OpenGL game in C++ that will have many objects created (enemies, player characters, items, etc.). I'm wondering the best way to organize these since they will be created and destroyed real-time based on time, player position/actions etc.

Here's what I've thought of so far: I can have a global array to store pointers to these objects. The textures/context for these objects are loaded in their constructors. These objects will have different types, so I can cast the pointers to get them in the array, but I want to later have a renderObjects() function that will use a loop to call an ObjectN.render() function for each existing object.

I think I've tried this before but I didn't know what type to initialize the array with, so I picked an arbitrary object type, then cast anything that wasn't of that type. If I remember, this didn't work because the compiler didn't want me dereferencing the pointers if it no longer knew their type, even if a given member function had the same name: (*Object5).render() <-doesn't work?

Is there a better way? How to commercial games like HL2 handle this? I imagine there must be some module etc. that keeps track of all the objects.

like image 987
Tony R Avatar asked Apr 19 '09 04:04

Tony R


2 Answers

I'm not sure I fully understand the question but I think you are wanting to create a collection of polymorphic objects. When accessing a polymorphic object, you must always refer to it by a pointer or a reference.

Here is an example. First you need to set up a base class to derive your objects from:

class BaseObject
{
public:
    virtual void Render() = 0;
};

Then create the array of pointers. I use an STL set because that makes it easy to add and remove members at random:

#include <set>

typedef std::set<BaseObject *> GAMEOBJECTS;
GAMEOBJECTS g_gameObjects;

To add an object, create a derived class and instantiate it:

class Enemy : public BaseObject
{
public:
    Enemy() { }
    virtual void Render()
    {
      // Rendering code goes here...
    }
};

g_gameObjects.insert(new Enemy());

Then to access objects, just iterate through them:

for(GAMEOBJECTS::iterator it = g_gameObjects.begin();
    it != g_gameObjects.end();
    it++)
{
    (*it)->Render();
}

To create different types of object, just derive more classes from class BaseObject. Don't forget to delete the objects when you remove them from the collection.

like image 35
Adam Pierce Avatar answered Oct 20 '22 00:10

Adam Pierce


For my soon-to-be personal game project, I use a component-based entity system.

You can read more about it by searching "component based game development". A famous article is Evolve Your Hierarchy from the Cowboy programming blog.

In my system, entities are just ids - unsigned long, a bit like in a relational database. All the data and the logic associated to my entities are written into Components. I have Systems that link entity ids with their respective components. Something like that:

typedef unsigned long EntityId;

class Component {
    Component(EntityId id) : owner(id) {}
    EntityId owner;
};

template <typename C> class System {
    std::map<EntityId, C * > components;
};

Then for each kind of functionality, I write a special component. All entities don't have the same components. For example you could have a static rock object that has the WorldPositionComponent and the ShapeComponent, and a moving enemy that has the same components plus the VelocityComponent. Here's an example:

class WorldPositionComponent : public Component {
    float x, y, z;
    WorldPositionComponent(EntityId id) : Component(id) {}
};

class RenderComponent : public Component {
    WorldPositionComponent * position;
    3DModel * model;
    RenderComponent(EntityId id, System<WorldPositionComponent> & wpSys)
        : Component(id), position(wpSys.components[owner]) {}
    void render() {
        model->draw(position);
    }
};

class Game {
    System<WorldPositionComponent> wpSys;
    System<RenderComponent> rSys;
    void init() {
        EntityId visibleObject = 1;
        // Watch out for memory leaks.
        wpSys.components[visibleObject] = new WorldPositionComponent(visibleObject);
        rSys.components[visibleObject] = new RenderComponent(visibleObject, wpSys);
        EntityId invisibleObject = 2;
        wpSys.components[invisibleObject] = new WorldPositionComponent(invisibleObject);
        // No RenderComponent for invisibleObject.
    }
    void gameLoop() {
        std::map<EntityId, RenderComponent *>::iterator it;
        for (it = rSys.components.iterator(); it != rSys.components.end(); ++it) {
            (*it).second->render();
        }
    }
};

Here you have 2 components, WorldPosition and Render. The Game class holds the 2 systems. The Render component has an access to the position of the object. If the entity doesn't have a WorldPosition component, you can choose default values, or ignore the entity. The Game::gameLoop() method will only render visibleObject. There is no waste of processing for non-renderable components.

You can also split my Game class into two or three, to separate display and input systems from the logic. Something like Model, View and Controller.

I find it neat to define my game logic in term of components, and to have entities that only have the functionality that they need - no more empty render() or useless collision detection checks.

like image 150
Splo Avatar answered Oct 19 '22 23:10

Splo