Entity-Component Design Questions

Started by
13 comments, last by Azaral 11 years ago

Okay. That makes sense. So for performance critical systems avoid the iterating through entities over and over again while processing them. Instead, opt to synchronize with an optimized format for that system and use that data instead.



Advertisement
Yes. You might for example use a physics engine such as Box 2D. That doesn't stop you having a physics component to handle the connection between physics and game logic, it would just not be responsible for actually updating the physics and would not need to store the physics data.

2. How do most people deal with changes to the component list? Do they use the observer pattern to inform systems when an entity changes or does the system query the master list every time to find the entities that match its criteria. The observer pattern is the way I was thinking.

The preferred way to handle changes is to have other systems poll the components. E.g. the position of an entity is used by the render system every frame. This is okey for data that is updated most the time, but it can quickly become inefficient for transient changes.

An example of this could be when a monster dies. A possibly bad way to handle this is to add a component that indicates that this monster is now dead, ur using a flag in a component that already exists. This flag would then continuously have to be monitored at all monsters, but all systems that depend on the fact. E.g. sound system playing special sound, render system drawing special animations, score system updating player score, achievement system taking note of kills. In this case, it may be better to use the observer pattern.

4. Is it okay to have some inheritance at the component level or would this break the design? Based on what I know, I can't imagine it would break the design. I wanted for instance my graphics system to be able to find all entities that contain a VertexBuffer component, but I also want my material system to be looking for a particular type of VertexBuffer component (say one that provides texels).

I wouldn't say it is wrong, but it would kind of be an anti pattern to ECS. The whole idea with ECS is to get away from inheritance hierarchies.

5. My understanding is that most systems contain a reference to an entity by entity ID and not by pointer. Why is that? Is it common for the pointer to change, but the ID to remain the same? If so, what scenarios would that occur in? Does constant lookup not cause performance issues?

Pointer, shared pointer or entity reference, doesn't really matter. It depends a little on what language you use. Of course, you must make sure to avoid dangling pointers. It may be a good idea to use the observer pattern to catch the case where entities are destroyed.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

I wonder,what are you using the templateparameters for? I'm still trying to find a good design, too.

This is called Curiously recurring template pattern, which has some interesting properties.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

In my system I do the following: (I program using C++)

An entity is nothing more than a unique ID value. This is what is going to bind the entity's components together. There will exist an entity manager which will be responsible for assigning ID's to new entities and add and removing components from the entity.

A component is nothing more than a very small and defined set of data. It has a little data as possible. The component data is stored in an unordered_map which is then stored in a vector. Each index of the vector represents a layer or state of the game (viewing the galaxy map vs viewing the research menus). The map uses entityID's as its key. Thus, to access the health component of an entity, it would just be a matter of healthComponent[currentLayer][entityID]. The component containers are also kept outside of everything, even the systems. This allows for the easiest access. Nothing is assumed. Position component is simply that, an x value and a y value. If it can be rotated, it will have the rotation component, which will just be a value denoting it's current orientation. The manner of how it is rotated is determined by other components. Components that are purely boolean (contain nothing more than a bool value) are probably going to be a reverse list. Instead of the entity being the key of a map, the entity will instead be a value stored in a vector. One such example would be the clickable component, which denotes if an entity can be clicked on with the mouse. It is faster to simply go through a vector and grab entityID's than to go through a map and get values of the keys.

A system is also defined with as few duties as possible. For example, the rendering system just draws images to the screen, nothing more. It doesn't occlude, the occlusion system does that. It doesn't determine animation state, the animation system does that. Each system is passed the maps of the components it cares about. Before it performs an action, it will check to see if the entity it is about to act upon has all the necessary components for the action, and if not it simply goes to the next entity. If a system makes a change to an entity that would be considered an event, such as an entity dying, then that system will return a list of entities that has that occured. If the damage system has reduced an entity's health to zero, it would return this list. Those entities would then gain the dead component (or to be more exact, added to the list of dead entities). Systems that act on dead entities would then act on this entity and systems that act on live ones would not.


This topic is closed to new replies.

Advertisement