Entity component system, component collection?

Started by
3 comments, last by haegarr 9 years, 9 months ago

Well I'm having some doubts while implementing an ECS, I'll try to explain as best as I can...

I'm using this java implementation of the ECS:

https://github.com/adamgit/Entity-System-RDBMS-Inspired-Java/tree/master/EntitySystemJava/src/com/wikidot/entitysystems/rdbmswithcodeinsystems

Lets take an example to see my problems with the ECS implementation. We have a side scrolling platformer game (metal slug, flashback, whatever tongue.png). We have the man entity (it could be the player or an enemy) with many components (position, weapon, etc.). What if we want to have several sprites/animations for the entity? (running, jumping, etc.)

I've thought some solutions:

1. Collections of components, so a "man" can have multiple sprite/animation component. That involves some changes in the ECS base code, chaging the entitymanager to fit lists of components.

In the graphics subsystem we will render every sprite/animation that is active.

We will have another subsystem to take care of which sprite/animation in the list of an entity is active or not, we can call it ManStateSubsystem. It will look into ManState to activate/deactivate the sprites/animations.

If we do this the graphic subsystem will just render active sprites/animations. But it will also go through many inactive components all the time.

2. Complex component, a bigger component that holds multiple components (a list of sprites, a list of animations, a list of sounds, etc.), it could be "ResourceComponent" and it holds all the assets related to the player (we could have empty lists in certain situations).

Similar to previous method, the graphics subsystem will also render active items, but now they could be sprite/animation and this new complexGraphicalComponent, which will need more code.

Same "ManStateSubsystem" to take care of activating/deactivating resources.

Similar issues as previous solution, traverses many inactive components.

It will also need more memory (we have sprite and animation lists inside the complexGraphicalComponent even if we only have 1 sprite).

For me it looks a little bit better than previous method, since we have resources grouped in a single component, rather than having lists of components.

3. Complex component, we have the same complexGraphicalComponent, but instead of rendering this component, we will have to remove/add current animation/sprite as a component to the entity.

Graphical system will only handle sprite/animations, and it won't check wether they're active or not.

ManStateSubsystem will take care of removing/adding components to an entity (implies adding removeComponent).

This approach seems like it's not breaking that much the concept behind ECS.

It has a limitation: an entity can't have more than 1 sprite and animation, so we won't be able to render 2 sprites for a single entity (looking at our example we won't be able to draw different trousers and shirts inside a single entity).

How would you solve this situation??

Advertisement

My solution is that a SpriteComponent refers to the current sprite (which is a resource), so that the rendering sub-system has exactly one component where it can find the active sprite. If the sprite is dynamic, i.e. it can be exchanged dependent on the situation, then there must be a controlling component for that. E.g. a controlling component that assesses the current world state, detects relevant situations, and exchanges the reference to the sprite resource inside the sprite component. The pool of possible sprites is part of the controller and not of the entity directly. Dynamic sprites which are time driven are handled similarly: Here the controlling component is an animation.

My solution is that a SpriteComponent refers to the current sprite (which is a resource), so that the rendering sub-system has exactly one component where it can find the active sprite. If the sprite is dynamic, i.e. it can be exchanged dependent on the situation, then there must be a controlling component for that. E.g. a controlling component that assesses the current world state, detects relevant situations, and exchanges the reference to the sprite resource inside the sprite component. The pool of possible sprites is part of the controller and not of the entity directly. Dynamic sprites which are time driven are handled similarly: Here the controlling component is an animation.

When you say "controlling component" you refer to an actual component, or a subsystem?? For what I get you are using a subsystem to refresh current sprite/animation, something like I said in the 3rd solution. If an entity has a group of animations, the groupOfAnimationSubsystem will change the reference to the current animation depending on player state (running, jumping, etc.); if an entity has a group of sprites, the groupOfSpritesSubsystem will change the reference to the current sprite.

But what if you want to render 2 sprites for the same entity? I can't see a clear way of doing that, I always end up with a bigger component, something like "currentGraphics" that can contain more than 1 sprite and/or animation (or other effects).

By the way, you say "the pool of possible sprites is part of the controller", so that controller will be a component? Something like SpriteListComponent?

Animations should not be components. Most things in your game should not be components. The animation module should have absolutely zero dependencies on your game object (entity) module.

You have an AnimatedSpriteDefinition. This includes the sprite sheet and the list of possible animations with timing information and so on. It may includes physics/collision information for those animations and frames, or you might have a separate object that represents those (so your rendering and physics modules are entirely non-coupled).

You can then have the graphics system create AnimatedSpriteInstance objects - which are managed in its own internal data structures that again have absolutely nothing to do with your game objects or components - that reference those definition objects. It can display and animate instances on its own. You can compile, link, and test your graphics module without ever compiling or linking a single component.

The game objects then provide data for initializing new animated sprites. The AnimatedSpriteComponent might contain the name of an animation file. When it's created, it asks the animation system to load the animation, then it asks the graphics system to create an instance of that animation. It stores the handle given by the graphics system to a shared glue system allowing physics updates to move the graphics object. When the component is destroyed, it tells the graphics system to destroy its sprite instance.

Your rendering system is going to include some kind of spatial scene graph for efficient rendering that has no direct purpose or parallel in the ECS architecture, and the ECS architecture likewise has surprisingly little direct applicability to the rendering system (though the idea of applying data-oriented design is still quite relevant, of course).

The same thing happens in physics. It's usually more obvious in physics since you're typically using a third-party library like Box2D or Havok or PhysX or Bullet or Farseer or whatever which doesn't even make it _possible_ to use your ECS' components directly as these libraries completely encapsulate their own efficient physics-oriented data structures and algorithms.

Don't worry about breaking the concepts of ECS. ECS is just one possible way to use components. Your job as a game engineer is to build systems that support your game, not to try to shove your game into the latest Reddit r/gamedev/ engine architecture fad. Use the concepts of ECS when and where they provide actual benefit. Use other component models where those make more sense. Bend the rules when the rules are getting in your way.

Sean Middleditch – Game Systems Engineer – Join my team!

As ever with ECS: There is no single way...

When you say "controlling component" you refer to an actual component, or a subsystem?? For what I get you are using a subsystem to refresh current sprite/animation, something like I said in the 3rd solution. If an entity has a group of animations, the groupOfAnimationSubsystem will change the reference to the current animation depending on player state (running, jumping, etc.); if an entity has a group of sprites, the groupOfSpritesSubsystem will change the reference to the current sprite.
But what if you want to render 2 sprites for the same entity? I can't see a clear way of doing that, I always end up with a bigger component, something like "currentGraphics" that can contain more than 1 sprite and/or animation (or other effects).
By the way, you say "the pool of possible sprites is part of the controller", so that controller will be a component? Something like SpriteListComponent?

It depends on how the ECS is implemented. Components may be real objects and have behavior implemented, or else they may be data containers stored in sub-systems, or they may be descriptions for data in sub-systems. However, it does not really change the concept of what I've written above.

For what its worth, here is a more complete description: In my implementation the attachment of a SpriteComponent with an entity causes a Sprite element to be reserved within the SpriteServices (a Services is my implementation of a sub-system). A Sprite element refers to a SpriteResource where the actual image data is available. A SpriteController is a Component that defines a behavior, namely a kind of dynamics on top of a Sprite element. It causes an installment in the SpriteServices. This thing is defined not to target a SpriteComponent but a Sprite element. Doing such a thing means that instances of the same type of elements inside a sub-system may come from different sources, perhaps but not necessarily all different components.

Yes, the controller is a component, because in ECS you want to define that and how the sprite of an entity will be dynamic. A different kind of dynamic control means a different type of controlling component. However, I usually do not use something like a SpriteListComponent, because this would be a too generic component. As mentioned above, the actual sprites are all available as SpriteResource. The sprites in the world are available as Sprite elements in the sub-system. What any sprite control requires is (a) a reference which Sprite element to alter (i.e. which Sprite element belongs to the original SpriteComponent of the entity), and which SpriteResource to be set into the Sprite element under which situation. This is definitely more specific than a SpriteListComponent.

Coming now to the problem of 2 sprites for the same entity. I do not support this. If one wants to have 2 sprites coupled in some way, it has to be expressed explicitly as relation between 2 entities. This requires an explicit ParentingComponent which, you guess it, causes a Parenting to be installed in the SpatialServices sub-system. A Parenting uses 3 Placement instances: It targets the Placement which originates from the PlacementComponent of the current entity (the own global placement), the Placement which originates from the ParentingComponent (the own local placement), and the Placement linked by the PlacementComponent (the global placement of the parent). BTW, here you have another example of the concept where the same kind of sub-system elements come from different types of components.
Of course, you can define the SpriteComponent and hence Sprite element with the ability to have more than one sprite. However, this means 2 references to SpriteResource instances, 2 placements (because there is ever a spatial relation, too), perhaps 2 animation controllers, … IMHO this is better solved with 2 entities as described above.

This topic is closed to new replies.

Advertisement