Component Based Entity System Question

Started by
11 comments, last by SiS-Shadowman 12 years, 7 months ago
Here's a very simple set-up that passes a renderer-pointer to the factory that is creating entities:[source lang=cpp]struct GameEngine
{
Renderer* renderer;
OtherSystem* blah;
};

class EntityFactory
{
GameEngine& engine;
public:
EntityFactory( GameEngine& e ) : engine(e) {}
Entity* LoadSomething(const std::string& file)
{
Renderer* r = engine.renderer;
....
}
};

class Game
{
EntityFactory factory;
public:
Game( GameEngine& e ) : factory(e) {}
};

int main(char** argc, int argv)
{
GameEngine engine = CreateEngine(argc, argv);
Game game( engine );
while(1)
{
game.Update();
game.Render();
}
}[/source]
Advertisement

Here's a very simple set-up that passes a renderer-pointer to the factory that is creating entities:


Okay, I kind of see now...would it also be a good idea to allow someone to add entity types to the EntityFactory so that they could request that type again and get all the components added to it that the user specified?

And with this method, I will need a factory...for pretty much every system correct? Sound \ Physics \ Event \ Message \ Network \ State?

Engineering Manager at Deloitte Australia


[quote name='SiS-Shadowman' timestamp='1316006709' post='4861535']
My system is pretty similar to yours, but instead of the entities holding the attributes, components do. When another component requires the same attribute, it must say so when it's attached to the entity (via requirements). Anyways, I have a big entity system that consists of subsystems. Each subsystem handles ONE specific type of a component. The one system holds all renderables, the other one all collidables, and so forth. This way I can render all renderables "at once" (the subsystem obviously holds an entity => component dictionary) and do collision tests for all components in the other subsystem.

So basically you add one system per component (sometimes I do need a small hierarchy in components, so I've restricted my rule to having one subsystem per DIRECT subclass of component: all further subclasses are put into the same system). If you're interested, I can send you my sources.


It is not completely obvious to me why a sub-system holds a dictionary of entity -> component (I assume by component, it is the actual component the sub-system deals with) that may be because:

A. My components can keep references to attributes that the entity has. (If you need position from the entity in the dictionary)
B. My components have a reference to the entity that contains it.

Do your components not know about their entities?
[/quote]
Yes, in fact they do. This is because my entities don't have a list of components attached to them, instead the subsystems take care of that. I figured that I'll propbably never need to get ALL components of an entity, only a subset.


When creating an entity, it only references the entitysystem it has been created with. Upon adding a component, for examble your Renderable3D, the entity defers the call to the entity system, which in fact defers the call to the right sub-system. It will in return add the (entity, renderable) pair into it's dictionary.


Entity e = entitySystem.CreateEntity();
e.Add(alreadyExistingRenderable3DComponent);


I solved the attribute problem by allowing components to reference other components, in fact, each component type specifies a Template that describes what this component actually requires. For example a renderable would require a transformable (everything that can be rendered must have a translation). This requirement now changes the process a bit. Upon adding the Renderable component, the entitysystem verifies that ALL requirements are met and if they are, the component is added. Otherwise an exception is thrown, containing all requirements that are not met. (The same procedure is done upon removing a component).



Entity e1 = entitySystem.CreateEntity();

e1.Add(new Transformable());

e1.Add(new Renderable3D());

Entity e2 = entitySystem.CreateEntity();

e2.Add(new Renderable3D()); //< throws because the transformable component is missing



That very same template can be used to construct a component (because it is in fact a string => object dictionary + a list of required components) through a subsystem. My subsystems are not only responsible for calling update / draw on their components, the also serve as factories to create a component from a certain template. On top of that I have a template collection that describes an entire entity. This way I can create a template for a starship, store that template somewhere and finally create a thousand starships, only passing that template to the entity system.


var template = new EntityTemplate();
dynamic transformable = ComponentTemplate.FromType<Transformable>();
transformable.Position = new Point(10, 100, -15);
transformable.Orientation = new Quaternion(....);
dynamic renderable = ComponentTemplate.FromType<Renderable>();
renderable.Mesh = "bunny.x";
renderable.Material = "bla"
template.Add(transformable);
template.Add(renderable);

Entity entity = entitySystem.CreateEntity(template);
// Entity now contains 2 components (transformable and renderable)

// Both components will have all properties extracted from the template upon construction




FYI: I'm using IronPython to describe all my components & entities, so I can simply redefine them while the game is running (and hence my c# example using the "dreaded" dynamic).

*edit* I forgot to mention that when retrieving a specific component from an entity, you specify it's type. The entity simply delegates the call to the entity system which in turn delegates it to the subsystem, responsible for that type (this method is mostly used upon entity creation and when components are attached):




Transformable t = e.Component<Transformable>();

Renderable3D r = e.Component<Renderable3D>();



*edit2* So to sum it up, the ENTIRE state is kept in the entity system. All a user has to do is to have a reference to it. The entity system takes care of registering the components with the right sub-system. This way you don't need global access to the renderer because the right sub-system has access to it (because it was given the renderer during construction), no need for global access to the physics simulator because of the very same reason.


This topic is closed to new replies.

Advertisement