C++ Entity/Component System Setup Assistance

Started by
8 comments, last by Hunter_Ex 11 years ago
First, I feel necessary to state that I have done extensive reading and searching for my answers before posting - in fact, I rarely post asking questions that I know I can find answers for. However, I seem to be stuck with what should be an easy hurdle.
I'm trying to write a c++ entity/component system, and I'm wanting to make it as "true" as I can, meaning that I'd like as much as possible to be abstracted. I know there are as many variations to the E/C system as there are programmers, but my goal is to make this as open-ended as possible.
Having not programmed in several years, I've recently (last 3 months) read several C++ books, and many of them touched on this topic (Game Coding Complete, Game Programming Gems 5 & 6, etc.), but while I have an understanding of the concepts, I can't seem to get code to work. I've gone through several code sources available (Artemis-CPP, noah, entityx, Cistron, Skald, ...), and while I can get them to work from these already designed bases, when it comes down to modifying the code, I just seem to have a block. I follow it a certain amount, then get lost. I've also read through seemingly all the links similar posts have suggested, from t-machine.org, to Richard Lord's blog, to countless others. This concept just seems to not stick for me.
At the risk of being flamed, would someone be able to point me to a step-by-step tutorial to write the basics of this system, or maybe post some stripped down code. By stripped down, I mean no error checking, no superfluous code - just the Entity/Component/System/Manager structures.
I suppose the last thing I should post is my understanding of how this works, in case that's where my problem lies:
An Entity is represented by simply an unsigned int, possibly having a friendly string name variable for easy debugging.
A Component is represented by a series of POD variables, just holding information relating to that single attribute/purpose
A System fires event messages when things happen in the game/app, such as collision, etc.
A Manager acts as middle ground between levels, linking Components to Entities, reacting to events and modifying Component data appropriately, etc.
I would truly appreciate it if someone could assist me, or even provide me with skeleton code, which I can then build on. It frustrates me that I've been unable to get past this, when it seems like a straight-forward implementation.
Advertisement

Hey taurusrow

I have been experimenting with component based object system now for a couple of years and the results have been getting better and better each time, currently I am actually streaming my current programming project live on http://www.twitch.tv/devmoon

I am using a very decoupled component/subsystem approach where each subsystem is completely independent and currently I have these systems but it will be more later

  • Transform
  • Physics
  • Collision
  • Timer
  • Editable
  • Render

To answer your questions

An object consists of the following

  • Unique ID
  • Object name (a pointer to a template that keep tracks of the name it was instanced with)
  • Array or component pointers
  • Internal messaging system (being able to communicate with the components)

A component consists of

  • Pointer to the object its attached to (so it can communicate)
  • Custom data its working on (position in the transform component etc..)
  • Pointer to the subsystem

A subsystem consists of

  • A vector of components (that is pre allocated)
  • Updates the components that have been used by any object

From my experience component based object systems is not some kind of "solve all your problems" but just another way to manage your game objects. You still need to craft it to fit your needs.

To update everything I have an ordered list of all my subsystems and call their update method

Here is also a script example of how it can be used (lua script)


sample_object =
{
	on_created = function(self)
	
		self:add_component("Transform")
		self:add_component("Physics")
		self:add_component("Collision", {width = 10, height = 10})
		
		self:add_component("Render")
		
		self:add_component("Editable")
		self:add_component("Timer", {[70] = instance_destroy})
	end,
	
	on_collision_enter = function(self, other)
	
		if (other.solid) then
			instance_destroy(self)
		end
	end,
	
        -- if there is no render method there is no overhead of trying to call one
	on_render = function(self, x, y, z)

                -- some custom draw code here if needed
	end
}

I do stream programming almost every day and you can ask me anything and I might make all the code available for public at a later date

Good luck with the component systems it is really fun to work with smile.png

Blekinge Institute of Technology
Twitter [twitter]devmoon[/twitter]
Homepage http://devmoon.se
Stream http://twitch.tv/devmoon

There are many possible approaches to an Entity/Component-system. Kristoffer Lindström already made a good starting point, but I'd like to present you a slightly modified method, which further decouples components and systems:

In this method, your components wouldn't have a pointer to a sub-system (which I'm going to referer to as "systems" from now on). Your systems wouldn't have a list of components, too. Instead, you would store all systems in a list, and in a generic "update" method you would implement the functionality. Systems would then act on Entities based on what components they have - a render system might pull out all entities with translation and model, a physics system will search for entities with translation and a bounding volume.

Main advantage here is that messaging between systems, entities and components is neglectible. You wouldn't need any messaging at all for the basic functionality. Additionally, this approach is even more decoupled - components are POD structures, that don't know anything about systems, or even that a system exists. Components also don't know about the entitiy that holds them.

While both approaches are plausible, I prefer mine (*duh*), because for the given reasons. But in the end its probably a matter of personal choice, while I still think it would be easier to implement an approach similar to mine, since you don't need a complex messaging system, which might be a hard thing to start with.

Yea that is the charm of the component/entity system, there is so many variations of it. My version integrates nicely with my lua implementation and allows me to do what I need, in the end the requirements you have on your engine/game will decide how sometime as important as the object management will be done.

You can also do really easy and slimmed component implementations, and actually I am using something similar to your technique Juliean when creating particle systems.

Blekinge Institute of Technology
Twitter [twitter]devmoon[/twitter]
Homepage http://devmoon.se
Stream http://twitch.tv/devmoon

@Kristoffer: Thanks for the reply and further explanation. I will look for your streaming to see if I can pick anything up

@Juliean: I appreciate your input as well

I'm going to keep trying to work at it, or find some sort of step by step tutorial to get the first parts set up and functional. The Interfaces to create the components and systems, using the correct smart pointers for references, etc. I really like the idea of the design, and Kristoffer, I agree - it seems like it is really fun to work with. Especially once you get into it and can create editors and such which just tag on components to entities.

Hi Taurusrow,

I've done a fair bit of ECS programming myself. If you look at my journal (link in my Sig), you can find some posts where I got through my 1st version of ECS, and then when I modified it, and created a 2nd version.

The first version had component containing both Logic and Data. It communicated with other components via an event/messaging system. It worked OK for what i was doing, but I wasn't real thrilled with how the messaging was working.

So, I created another ECS system (called the Escape system, found here) which mimics more of what Juliean describes. There is no messaging, only systems operate on the components data. The systems can operate on a single Component, or on an entity that contains multiple specific components; the system, upon initialization sets what type of component an entity must have forit's Update to be called with that entity.

Here is some code where i setup some systems, and I create some components ad link them to an entity:
 
    pWorld = Esc::TWorld::GetInstance();
 
    PhysicsSystem = new TPhysicsSystem(mpSpace);
    RenderingSystem = new TRenderingSystem(app);
    DamageSystem = new TDamageSystem();
    DeathSystem = new TDeathSystem(mpSpace);
    InputSystem = new TInputSystem(app);
    EnemySystem = new TEnemySystem();
 
    pWorld->AddSystem(InputSystem);
    pWorld->AddSystem(EnemySystem, 1000, true);
    pWorld->AddSystem(PhysicsSystem);
    pWorld->AddSystem(RenderingSystem);
    pWorld->AddSystem(DamageSystem);
    pWorld->AddSystem(DeathSystem);
 
    Esc::TEntityPtr Entity1;
 
    Entity1 = pWorld->CreateEntity();
    TGraphicsObject* graphicComp(new TGraphicsObject(Utilities::ImageGet("gfx/player.bmp")));
    TPhysicalObject* physicalComp;
    THealth* healthComp(new THealth(100, 100));
    TInput* inputComp(new TInput());
 
    // Create a Physics object
    physicalComp = new TPhysicalObject(mpSpace, pBody, pShape, 200.0f);
 
    pWorld->AddComponent(Entity1, graphicComp);
    pWorld->AddComponent(Entity1, physicalComp);
    pWorld->AddComponent(Entity1, healthComp);
    pWorld->AddComponent(Entity1, inputComp);
 
    pWorld->SetGroup(Entity1, "Player");
    pWorld->AddEntity(Entity1);
Here is code for a rendering system. Look at the Initialize() function, it defines it only wants to deal with entities that have a Physical Object Component, and a graphical Object component.

TRenderingSystem::TRenderingSystem(sf::RenderWindow *pApp) :
  Esc::TSystem(), mpApp(pApp)
{

}
TRenderingSystem::~TRenderingSystem()
{

}

void TRenderingSystem::Update(Esc::TEntityPtr entity, uint32_t tickDelta)
{
    TPhysicalObject *physicalObject =
      static_cast<TPhysicalObject*>(entity->GetComponent("PhysicalObject"));
    TGraphicsObject *graphicObject =
      static_cast<TGraphicsObject*>(entity->GetComponent("GraphicsObject"));

    graphicObject->GetSprite()->SetPosition((int)physicalObject->GetBody()->p.x,
                          (int)physicalObject->GetBody()->p.y);
    graphicObject->GetSprite()->SetRotation(physicalObject->GetBody()->a*(180.0f/PI));
    mpApp->Draw(*(graphicObject->GetSprite()));

}
void TRenderingSystem::Initialize()
{
    // Set which components we want to deal with
    Esc::TSystem::HandleComponent("PhysicalObject", true);
    Esc::TSystem::HandleComponent("GraphicsObject", true);
}
Here is code where I setup the graphics component, just to give you an idea:

class TGraphicsObject : public Esc::TComponent
{
public:
    TGraphicsObject(sf::Image *image) : Esc::TComponent("GraphicsObject"), SfmlImage(image)
    {
        if (image) {
            SfmlSprite = new sf::Sprite();
            SfmlSprite->SetImage(*SfmlImage);
            SfmlSprite->SetOrigin(SfmlImage->GetWidth()/2, SfmlImage->GetHeight()/2);

            SfmlSprite->SetRotation(0*(180.0f/PI));
        }
    }
    ~TGraphicsObject() { delete SfmlSprite; }

    bool IsImage() { return (SfmlImage != NULL); }
    sf::Sprite *GetSprite() { return SfmlSprite; }

    void GetSize(uint32_t &width, uint32_t &height)
    {
        width = SfmlImage->GetWidth();
        height = SfmlImage->GetHeight();
    }

private:
    sf::Image *SfmlImage;
    sf::Sprite *SfmlSprite;

};

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

There is a portable very good C++ implementation of an Entity-Component system, available at https://github.com/alecthomas/entityx. If you want to do an implementation of your own, please have a look at the readme of this system first.

I think this implementation fulfills most requirements on easy-of-use, decoupling and efficiency (including what Juliean stated above). It also has an built-in support for callbacks, to be used for low frequency events.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

On messaging systems, I think you could do away with it entirely in lieu of using components to transfer the message.

For example, you are testing for collisions. Instead of throwing a message to something that, hey, a collision occurred, you would simply add a collided component to the entities in question, the data of which would be the ID of the entity that it collided with. Then any systems that cared about collisions would look through the list of collided components and grab all of the necessary data from the other components it cares about and do what it does.

I'm surprised no one linked to Understanding Component-Entity-Systems.

I am surprised by the emphasis on messaging. The system I am using has

  • no implicit messaging: I couldn't figure out a proper behavior that would make sense in general
  • no parent-child relationships, admittedly for the lack of time in implementing those
  • no need to poll for components: I operate on them directly instead

Object name (a pointer to a template that keep tracks of the name it was instanced with)

A pointer to a template... of the name... it was instanced with. So it's variable name or not?

Previously "Krohm"

I'm surprised no one linked to Understanding Component-Entity-Systems.

I am surprised by the emphasis on messaging. The system I am using has

  • no implicit messaging: I couldn't figure out a proper behavior that would make sense in general
  • no parent-child relationships, admittedly for the lack of time in implementing those
  • no need to poll for components: I operate on them directly instead

Object name (a pointer to a template that keep tracks of the name it was instanced with)

A pointer to a template... of the name... it was instanced with. So it's variable name or not?

Yea that was kind of badly worded, what I meant is that each object in the scene was created using something like



local inst = instance_create("ObjectName")


-- where this could be an object
ObjectName =
{
   on_created = function(self)
      
      self:add_component("Transform")
   end
}

So the object holds a pointer to an ObjectTemplate that has the string name and a connection to the Lua table.

My messaging system operates by components binding a callback to a message name on the object, whenever a component posts something the object calls all the other components that subscribed to that particular message. This is mostly used to hook stuff when components gets added or removed.

Blekinge Institute of Technology
Twitter [twitter]devmoon[/twitter]
Homepage http://devmoon.se
Stream http://twitch.tv/devmoon

This topic is closed to new replies.

Advertisement