0
\$\begingroup\$

I'm trying to learn and understand the ECS (Entity Component System) so that I can create a game using this design pattern but I've got a lot of things that I still don't understand.

Lets say I've got a PositionComponent and a MovementSystem or PhysicsSystem. The PhysicsSystem will heavily rely on the PositionComponent since in order to calculate, for example a rigid body motion, it needs the x and y positions (in a 2D game) wich is contained by the PositionComponent.

What is the relationship between Components and Systems? How does the MovementSystem get the x and y values from the PositionComponent?

\$\endgroup\$
  • \$\begingroup\$ I don't think you should see systems as a thing. I think you should see everything as a component. Components should provide interfaces and require interfaces. If a physics component requires a position interface, that's fine. Describing relations in terms of interfaces helps separate the implementation of a component from what it provides. \$\endgroup\$ – Ben Dec 7 '14 at 10:16
  • 1
    \$\begingroup\$ Related: gamedev.stackexchange.com/questions/31473/… \$\endgroup\$ – Ryan Dec 7 '14 at 11:32
  • \$\begingroup\$ @Ben could you show me a basic example code so that I can get a better understanding? \$\endgroup\$ – Marko Kitonjics Dec 7 '14 at 11:56
  • \$\begingroup\$ bitsquid.blogspot.com/2014/08/… \$\endgroup\$ – Sean Middleditch Dec 8 '14 at 0:53
1
\$\begingroup\$

One way for a system to know about components is by it knowing that every entity it has access to when it updates will have some combination of component objects.

For example, with a movement system:

void MovementSystem::Update(float deltaTime)
{
    for (int i = 0; i < this->GetEntityCount(); ++i)
    {
        Entity *entity = this->GetEntity(i);

        /* It's known that all the entities available in this system have
        at least a Velocity and Position component so they can always be gotten here */
        VelocityComponent *velocityComponent = entity->GetComponent<VelocityComponent>();
        PositionComponent *positionComponent = entity->GetComponent<PositionComponent>();

        positionComponent->x += velocityComponent->x * deltaTime;
        positionComponent->y += velocityComponent->y * deltaTime;
    }
}

As for how it can be guaranteed that a system will only be updating entities with the components it is interested in accessing, there are different implementations. The Artmemis Framework (originally written in Java) is an example of one way of doing it: http://gamadu.com/artemis/

\$\endgroup\$
  • \$\begingroup\$ This tightly couples the movement system with both VelocityComponent and PositionComponent. This isn't such a bad thing in this example, but doing this all over the place will result in pretty unmaintainable code. Interfaces should be preferred in situations like this to reduce coupling. \$\endgroup\$ – Ben Dec 7 '14 at 12:51
  • \$\begingroup\$ I think it could be argued that an interface is being used here, at least conceptually. "Has both a VelocityComponent and a PositionComponent" is the interface that the system is expecting each entity it gets to conform to, and it's up to the code managing the systems to ensure that. There's flexibility gained when new systems can be implemented that just start using an interface implicitly like this. Unfortunately, with most languages games are written in, there aren't easy ways to get that same flexibility and still have statically typed interfaces for every combination of components. \$\endgroup\$ – Mars Dec 8 '14 at 0:06
  • \$\begingroup\$ @Mars By looking at: Entity *entity = this->GetEntity(i); How can I make the system know wich entity contains it? Is the MovementSystem class a big container that holds all the Entities that contain movement? Or do I create an instance of the MovementSystem for each entity that has movement? \$\endgroup\$ – Marko Kitonjics Dec 9 '14 at 9:49
  • \$\begingroup\$ The movement system is basically a container of pointers to entity objects currently in play that match the set of components the system has been configured to be interested in. Whenever an entity is spawned, despawned, or the components it has changes, the engine notifies all systems so that each can check if they don't already contain the entity's pointer but its components match the combination the system's interested in (entity pointer gets added to system) or currently contain its pointer but its components no longer match the combination the system's interested in (pointer gets removed). \$\endgroup\$ – Mars Dec 9 '14 at 10:24
  • \$\begingroup\$ @Mars Should I create an instance of the System class for each system tpye and pass the entities to them or how should I implement this part? Could you provide me a source code or show me a simple example covering this part? Thanks in advance! \$\endgroup\$ – Marko Kitonjics Dec 10 '14 at 0:56

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.