2
\$\begingroup\$

Ok so I am just starting to grasp the whole ECS paradigm right now and I need clarification on a few things. For the record, I am trying to develop a game using C++ and OpenGL and I'm relatively new to game programming. First of all, lets say I have an Entity class which may have several components such as a MeshRenderer,Collider etc. From what I have read, I understand that each "system" carries out a specific task such as calculating physics and rendering and may use more that one component if needed. So for example, I would have a MeshRendererSystem act on all entities with a MeshRenderer component. Looking at Unity, I see that each Gameobject has, by default, got components such as a renderer, camera, collider and rigidbody etc. From what I understand, an entity should start out as an empty "container" and should be filled with components to create a certain type of game object. So what I dont understand is how the "system" works in an entity component system.

http://docs.unity3d.com/ScriptReference/GameObject.html

So I have a GameObject(The Entity) class like

class GameObject
{
public:
    GameObject(std::string objectName);
    ~GameObject(void);
    Component AddComponent(std::string name);
    Component AddComponent(Component componentType);
};

So if I had a GameObject to model a warship and I wanted to add a MeshRenderer component, I would do the following:

warship->AddComponent(new MeshRenderer());

In the MeshRenderers constructor, should I call on the MeshRendererSystem and "subscribe" the warship object to this system? In that case, the MeshRendererSystem should probably be a Singleton("shudder"). From looking at unity's GameObject, if each object potentially has a renderer or any of the components in the default GameObject class, then Unity would iterate over all objects available. To me, this seems kind of unnecessary since some objects might not need to be rendered for example. How, in practice, should these systems be implemented?

\$\endgroup\$
  • \$\begingroup\$ "Looking at Unity, I see that each Gameobject has, by default, got components such as a renderer, camera, collider and rigidbody etc." - this is incorrect. Each GameObject is guaranteed to have a Transform. The rest are only properties that will return that Component if present, otherwise they will return null. \$\endgroup\$ – Kelly Thomas Oct 8 '14 at 9:46
1
\$\begingroup\$

Another approach is to register your subsystems with the game object system. During registration, they provide component configuration parameters that identify what components must exist to consider an entity of interest during it's update pass.

Now you simply create your entities and associate components to them. These entities by default are inactive and not in the world simulation. Once they've been created with all their settings, you ask the game object system to activate the entity. During activation, the system registration configuration is compared to that of the entity and if a system's component needs are met, the entity is added to that system's view. You can send out events during this phase to inform systems of new entities so they can create internal resources for their update tick when it gets called.

Now during the update pass for each system, the system is presented with a list of entities to operate upon. The beauty of this is that components do not know of systems and the systems simply don't care how the components came into existence, just that they exist.

One of the main things I have come to like is keeping components and systems separate, particularly around lifetime management. Naturally systems need to know when they come and go for various reasons, but because components are often of interest to more than one system, it makes sense that their construction/destruction and storage be handled independently from systems.

\$\endgroup\$
1
\$\begingroup\$

Unity's Entity-Component-System implementation isn't an ideal model on which to base a custom ECS. Unity favors ease of use over strict adherence to the ECS paradigm and made lots of trade-offs to serve that end.

Where Unity falls short of a pure ECS is the lack of separation between data and logic. In a pure ECS components contain only data and the logic that operates on them live in separate systems. However, to facilitate GUI based data-binding, Unity's components have update methods with logic that operates on that component's data. One might think, "Well isn't that the point?, its OOP after-all" but that's the thing with ECS, the whole drive behind it is to keep data and logic separate.

If you want a better understanding of how "systems" come into play in ECS architecture I strongly recommend reading the following two articles. They do a great job of breaking it down:

What is an entity system framework for game development?

Why use an entity system framework for game development?

\$\endgroup\$
0
\$\begingroup\$

One of the main goals of ECS is to have classes as decoupled as possible, mainly components and systems. In this sense, I wouldn't make a component subscribe itself to the systems it needs to, because then suddendly you will find that you have components hooked up to Systems, and if you remove a system, you have to alter the respective components.

Take as an example a Position component, and think of the many ways it can be used in many different Systems. If you have the Position constructor subscribe to the different Systems, say, MovementSystem, CollisionSystem, etc, then suddendly, it's not so decoupled anymore, and intrinsecaly you will be binding Components just by creating then, which you might not always want.

In my ECS implementation, I have a factory class that is capable of creating components, and thus registers each component with the respective System. This means that all the coupling will happen here, and it can be easily configurable, allowing me to have multiple ways to instantiate the components without directly changing the components themselves. If you use factories, you will find that you can then take a step further and create files from where you can read entities and their associated components, pushing your game towards a data-driven design.

I hope this helps. As a disclaimer, take all this advice with a grain of salt, since I am not an expert.

\$\endgroup\$
  • \$\begingroup\$ I wouldn't subscribe each necessary component. I was thinking that If I had CollisionSystem then I would just subscribe a collider component. The system would realise that it needs a PositionComponent and ask the entity to provide a position component. If if can't, then create one for that entity. Would I be right in saying that components don't all need to be bound to a system and can co-exist with other components to allow those other components to function? \$\endgroup\$ – John Aug 21 '14 at 10:38
  • \$\begingroup\$ So the idea would be to have some sort of component C that to the system would represent a need for X Y Z components? And this C component would be the one subscribing to the Systems? How would the System access those components after, container_component->X, or entity->getComponent(X)? \$\endgroup\$ – rvalerio Aug 21 '14 at 11:13
  • \$\begingroup\$ Yeah well the systems will just store a pointer to the relevant entity and call GetComponent(X) like you said. \$\endgroup\$ – John Aug 21 '14 at 14:55
0
\$\begingroup\$

To expand on crancran's answer, I will share our experiences with the ECS we use at work.

Each component has the ability to be registered with a list of that component type. For example, our ModelComponent is registered with a ComponentList in it's create function, and removed in it's destroy function. Each frame, in the update loop, different systems are handed the component list(s) they need to operate upon. The ModelRenderer is handed the ComponentList as well as the ComponentList, for example. This keeps the data and the systems decoupled.

I some cases these lists are actually use to update the entities themselves - we iterate over all of the particle systems at a specific point in the frame to update them by calling ComponentList::Update() which invokes an Update method for each item (not using virtuals, but using template programming). The lists can also be split into active/inactive cases, and in some projects the lists are sophisticated and understand our portal system and staged updates.

One of the key aspects of ECS is that it takes awhile to get it right. I would encourage you to start working on components in a game and see what feels right. I do not believe there is yet a canonical, correct implementation out there.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.