Systems problems with Entity Component System architecture

Started by
2 comments, last by wintertime 10 years, 5 months ago

Im doing an engine (together with a game) for learning purposes. Til now I made it just with entities (which I actually call game::Object) and components, no systems. I did that way on purpose cause I knew I wouldnt manage to build one at first.

So Im handling the components work manually. Note that it is working like a charm, no real problems, except the amount of work to setup stuff, cause I dont have factories or data driven yet.

Basically my engine is like this:

App[renderer, input, sound, networking, hig perf timers]

-Game [state machine, fixed step loop]

--State [exclusive (one at a time), timer, holds layers]

---Layers [parallel (independent of each other), timer, holds objects]

----Objects[ holds components]

-----Components[type]

extra stuff(available to the user, not integrated directly on the engine)

- task machine[execute chainable tasks] (i use for stuff like fading or launching event after a delay)

- event machine[holds eve type - eve handler map] (used to eliminate dependencies)

if a state is deleted, everything dies with it, if a layer - every object, if a object - every component.

You can hold it externally cause they are all shared_ptr, but it wont execute till attached back on the hierarchy above.

I dont have "views" for the game, I just have a method Draw(interpolation) that is called after the fixed step loop.

game.fixedstep() // calls state.update->layers update

game.draw() // calls state.draw->layers draw

i.e. derived states: MainMenu, InGame, GameOver..

i.e. derived layers: bg, main, hud, pause menu, fade..

Till now I was doing the work with the components on the layers, by hard coding. (holding weak_ptrs to them on the layer, as objects killed must also kill its components)

Im trying to update the engine to use systems, so I can let it modular enough to be able to load everything from file. (so I wouldnt need to derive states and layers, only setup layouts from files)

But theres many things to solve with that systems addition..Give me some feedback..some nice ones o_ó. Lately Ive been thinking a lot and not getting anywhere.

I plan to add the systems to the layers, so the layer would automatically update all the systems it contains. The problem Im having is how to let the systems know about the components which they need to work with. Or you think systems should mess with multiple components of the same object ( messing with objects instead of components)?

I will have to handle different scenarios:

new obj added to the layer - systems need to know if obj got components they interested into

new component added to object - is object attached to layer? if so, same as above

obj removed from layer - systems need to know so they remove it from its "execution list"..?

component removed from object - is object attached to layer? if so, same as above

Note that objects and components dont have any link to systems, so, i.e., an object need to go trough layer so the layer can talk with the systems. Components have links to objects only, and objects with layers (m_pOwner). System would have link with layer only too.

Not sure how I do that. Im thinking on using a event machine on the layer, that systems can register themselves into. But how do I manage the events? Each new component need to launch a event on attachment? I dont like creating that rule for all new components.

(should each component have an "on attach" event, so the systems register themselves only to the specific event. Or should objects launch a generic "component attached" event, specifying the type on the data -> but that way all systems need to register to that event, and ignore the ones that they're not interested into..since all them would need that, should systems have a virtual VOnComponentAttached? hmm..I dont like that)

(Im not thinking in moving the components "acquisition responsibility" to systems, cause many systems might use the same components. But I do want to have custom allocation pools to hold components of the same type together. I think they'd be held on the layer also. But this is way ahead, Im delaying custom mem management.)

- mehh..sorry for utterly long and depressing post-

Advertisement

I'm thinking you are already at the point where you could take the components out of the entities and put all components of each single type together into something like a vector or pool as you call it. That would make it easier to create the systems when they just get 1 or 2 of those component vectors to iterate from beginning to end for doing their work.

If you delay it you will have to repeatedly beg all entities for some component, whether they have it or not, and the entities need to do useless type checking on all components every time you ask for one. That means you traded in programming the simple pool for programming temporary stuff inside the entity and still programming the pool later.

I wouldn't do attach events. Only add it to the pool. If the component is there it would know already which entity it belongs to from creating it; and the corresponding system will automatically find it inside the pool when it does its work.

I'm thinking you are already at the point where you could take the components out of the entities and put all components of each single type together into something like a vector or pool as you call it. That would make it easier to create the systems when they just get 1 or 2 of those component vectors to iterate from beginning to end for doing their work.

If you delay it you will have to repeatedly beg all entities for some component, whether they have it or not, and the entities need to do useless type checking on all components every time you ask for one. That means you traded in programming the simple pool for programming temporary stuff inside the entity and still programming the pool later.

I wouldn't do attach events. Only add it to the pool. If the component is there it would know already which entity it belongs to from creating it; and the corresponding system will automatically find it inside the pool when it does its work.

But if you take the entities out of the architecture, you will have to eventually search all components on the pool trying to find certain entity wont you? To me an entity object is a shortcut to its components. I was thinking in keep the entities even after having the pools, to make easier to access its components..

What do I do when a component need to inform other component on the same entity? Should this never happen? Should this kind of dependency be made at construction (i.e., sprite, collider and rigid body component requires transform component at construction?)

Do you have a case already where you need all components of an Entity(other than deleting it)? If not, I would follow YAGNI. If yes, can you move data between components to prevent it needing more than 1, 2 or maybe 3?

The thing with a single component informing another is, components could be made relatively dumb and the logic would then be inside the systems in an explicit form without much messaging.

In your example the sprite, collider and rigid body system would probably just access all position components and all of their type of sprite, collider or rigid body components. If they are sorted in the same way(for example by entity id) it shouldn't need a full search per component, but only a single linked iteration through both arrays.

This topic is closed to new replies.

Advertisement