C++ Port of Artemis Entity Component System Framework (In Progress)
Posted by ZBethel,
18 January 2012
·
6,774 views
This month is officially "wrap my head around Entity/Component Systems" month. I stepped away from coding for a bit and spent time researching different designs for handling game objects. Most interestingly, my search brought me to the Artemis Entity System Framework. Written in Java, the system is the best overall design I have seen so far (that's not saying much)--even if it is written in Java...just kidding. At any rate, I really liked what I saw so I used it as a reference for my system written in C++. In a way, it's really more like a port, without the reliance on RTTI (or whatever that class identification business is in Java). The architecture is virtually the same, but I took the liberty of writing things a bit differently to reflect the language differences.
Initially I considered using an std::map to relate entities to their component lists, but I really liked that they used a vector in Artemis to store all the entities. An O(1) lookup time is much better than O(log n) when you're dealing with several lookups per entity per frame. Like in Artemis, I opted to use a separate vector with removed entity indices. Whenever an entity is added, the system checks that vector first to see if there is a hole in the main vector. This reduces fragmentation and covers the case where the user removes several entities before adding one.
Unlike Artemis, I used an event system to decouple the entity manager and entity systems. The entity manager fires an event whenever a component is added, allowing the entity systems to check that the entity still has all of the required components. I figured that my game will use an event manager, so it made sense to integrate one now. Also, other subsystems could be notified whenever an entity is created/destroyed or a component is inserted/removed from a specific entity. The entity systems themselves contain a std::set< Entity* > data structure that holds all of the active entities. When it receives one of the previously mentioned events, it can check the entity to see if it should be added to or removed from the set.
Here's what I have so far in my main.cpp test program:
Here's the source for my TestSystem class:
If you look closely at the last line, you'll notice that the component system supports multiple components per type. This is another difference from the Artemis framework, which only allows one per type. The reason I chose to diverge from their design in that respect is because I can think of at least a few key cases where it would be really nice to have multiple components per type. For instance, if I have an articulate vehicle entity, I might have the chassis connected to the wheels. With this system, I could have four joint components--each one connected to a wheel.
At any rate. If anyone is interested in the code, I'd be happy to provide it. It's essentially just a port of Artemis with a couple nuanced changes and additions.
EDIT: I got sidetracked and I haven't made much progress since this post. I decided I would just post what I have: http://cse.taylor.edu/~zbethel/ArtemisPortCpp.zip
If you have any questions, feel free to ask.
Initially I considered using an std::map to relate entities to their component lists, but I really liked that they used a vector in Artemis to store all the entities. An O(1) lookup time is much better than O(log n) when you're dealing with several lookups per entity per frame. Like in Artemis, I opted to use a separate vector with removed entity indices. Whenever an entity is added, the system checks that vector first to see if there is a hole in the main vector. This reduces fragmentation and covers the case where the user removes several entities before adding one.
Unlike Artemis, I used an event system to decouple the entity manager and entity systems. The entity manager fires an event whenever a component is added, allowing the entity systems to check that the entity still has all of the required components. I figured that my game will use an event manager, so it made sense to integrate one now. Also, other subsystems could be notified whenever an entity is created/destroyed or a component is inserted/removed from a specific entity. The entity systems themselves contain a std::set< Entity* > data structure that holds all of the active entities. When it receives one of the previously mentioned events, it can check the entity to see if it should be added to or removed from the set.
Here's what I have so far in my main.cpp test program:
// Create the event manager and entity manager
evtMgr = new SGF::EventManager();
entMgr = new SGF::EntityManager( evtMgr );
test = new SGF::TestSystem(evtMgr, entMgr);
// Create an entity
SGF::Entity *e = entMgr->CreateEntity();
SGF::Transform *trans = new SGF::Transform();
entMgr->InsertComponent(e, trans);
while( !wnd.HasQuit() )
{
wnd.PumpMessages();
ID3D11DeviceContext *dc = graphics->GetImmDeviceContext();
IDXGISwapChain *sc = wnd.GetSwapChain();
{
wnd.SetAsRenderTarget(dc);
dc->ClearDepthStencilView(wnd.GetDSView(), 0, 1.0f, 0);
dc->ClearRenderTargetView(wnd.GetRTView(), D3DXCOLOR(0.0f,0.0f,1.0f,1.0f));
sc->Present(1, 0);
}
// This loops through any entities that match the bit flags for the component type. In this case, all it wants is a Transform component.
test->Process();
}
entMgr->DestroyEntity(e);
delete test;
delete entMgr;
delete evtMgr;
Here's the source for my TestSystem class:
// TestSystem.h /////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
#ifndef __TEST_SYSTEM_H__
#define __TEST_SYSTEM_H__
#include "EntityProcessingSystem.h"
namespace SGF
{
class TestSystem : public EntityProcessingSystem {
public:
TestSystem( EventManager *eventManager, EntityManager *entityManager );
virtual ~TestSystem();
protected:
static unsigned int TypeBits;
virtual void ProcessEntity( EntityManager *manager, Entity *e );
};
};
#endif
// TestSystem.cpp /////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
#include "TestSystem.h"
#include "EntityManager.h"
#include "ComponentMapper.h"
#include "Transform.h"
#include <assert.h>
using namespace SGF;
unsigned int TestSystem::TypeBits = (1 << CT_TRANSFORM);
TestSystem::TestSystem( EventManager *eventManager, EntityManager *entityManager )
: EntityProcessingSystem(eventManager, entityManager, TypeBits)
{}
TestSystem::~TestSystem() {}
void TestSystem::ProcessEntity( EntityManager *manager, Entity *e )
{
// Allows you to map the list as a specific component type.
ComponentMapper<Transform> tmap = manager->GetComponentList(e, CT_TRANSFORM);
// We can index a specific component of a specific type.
assert( 0 && tmap[0]->mat._11 );
}
If you look closely at the last line, you'll notice that the component system supports multiple components per type. This is another difference from the Artemis framework, which only allows one per type. The reason I chose to diverge from their design in that respect is because I can think of at least a few key cases where it would be really nice to have multiple components per type. For instance, if I have an articulate vehicle entity, I might have the chassis connected to the wheels. With this system, I could have four joint components--each one connected to a wheel.
At any rate. If anyone is interested in the code, I'd be happy to provide it. It's essentially just a port of Artemis with a couple nuanced changes and additions.
EDIT: I got sidetracked and I haven't made much progress since this post. I decided I would just post what I have: http://cse.taylor.edu/~zbethel/ArtemisPortCpp.zip
If you have any questions, feel free to ask.
Create a custom theme




