Updating Components

Started by
7 comments, last by haegarr 12 years, 6 months ago
I've been researching a lot into component based systems and have kind of come to point where I'm not really sure of the best way to update components per frame or control their update order. In all my reading I have basically found at least 3 different approaches.

  1. You have a component interface with a virtual Update() function. The entity that owns this component has an Update() function which iterates all it's components calling their Update().
  2. Similar to #1 except you use a signal/slot setup where components can subscribe to an OnUpdate event in entity that owns them.
  3. There is no such thing as Update() within components or entities. This update logic is moved to another class which manages a particular component type.

These all have there pros and cons which I'll briefly state:

1)
Pros:
- Simple to use and manage as behaviours are contained within each component.

Cons:
- Cost of virtual call overhead
- No clear way to order update calls between components (at least that I can see)

2)
Pros:
- Same as 1 except no virtuals.
- Fits in with current use of signals/slots for attribute change notification

Cons:
- Has some overhead but not sure if its more than virtuals?

3)
Pros:
- Solves the update call order problem as each component manager can be called in order based on the game/engine context.

Cons:
- Manager explosion! You could require a manager for every type of component. This could be really hard to maintain :/


Would really appreciate what others with experience on this topic have to say and what decisions they made in their systems, etc.

Cheers!
Advertisement
Please notice that updating an entity by simply iterating its components may not be sufficient. The overall architecture may need that specific (by type) components need to be updates before others, and that some components may need more than a single update step (look e.g. at this excerpt from Jason Gregory's Game Engine Architecture). Hence I've gone the way of sub-systems where belonging components are to be registered, and updating is left to be run by the sub-system. This doesn't exclude components to have their own update functions if necessary. Furthermore, there may be a dependency in the update order. Think e.g. of parenting the placement of models. This kind of problem can be solved using a dependency graph inside a sub-system where appropriate.
Hi Shael,

I found myself utilizing a combination of all those techniques based on the purpose of the component.

  1. Components contain their own behavior and conveniently provide a virtual Update() for asynchronous updates. The behavior of an Entity is defined by the composition of its component's behaviors.
  2. Components communicate to each other using Publish/Subscribe Pattern based messaging system.
  3. Component have their own Manager which simplifies managing Components by group. In some cases, I create temporary data structures (queue, stack, list, trees, graphs, etc) to hold a set of components/entities that require update in a specific group or order.
Ultimately, you have to experiment with the techniques to find one or a hybrid that can meet your needs.
I prefer your third option. In my project, components are data-only. The various subsystems aren't organized by component type, but by the more typical separation of duties in games. So, I have a renderer, a physics controller, a game logic controller, etc. Each subsystem knows about the component types necessary to do it's job. The renderer uses RenderableComponent and XformComponent. The physics controller uses XformComponent and MovableComponent. Some components are only used by one system, some by several. Each system has an Update( float dt ) method, which I call in the game loop. The systems handle any component-to-component communication and update component data as needed.

I don't have it set up yet, but my goal is to get to the point where I can generalize the systems to the point that I can feed it a script file to define it's update logic and which component types are to be used.
+1 to option 3.

The way I see it, the engine is made up of a bunch of sub-systems which provide functionality that any given game object may or may not need. Game objects then are made up of various components, which are the pieces of them specific to the various sub-systems.

So if the object needs physics control/interaction, it'll have a physics component, which is managed (owned) by the physics system. If it needs AI, it'll have an AI component managed (owned) by the AI system.

Game object construction may consist of wiring components together based on their dependencies. For instance, both the physics and the AI systems may be dependent on some sort of World Position component which they may want to read from or write to in order to do their work. So the game object would need to have such a component, which it then exposes to those other components that need it.

There's no need for extra "managers" because you need to have those engine sub-systems anyway.

Another potential added benefit inherent to this approach is cache coherency. If AI processing is performed within a single engine system, rather than by various component instances scattered among the mass of game object components, then the processor is likely to be running the same code consecutively throughout AI processing, producing fewer cache misses. And this also presents the opportunity for sub-systems to manage components within memory pools, essentially placing their components in consecutive memory as well, also potentially leading to fewer cache misses. This is not to say that one should get carried away with premature optimization, but just to point out that this approach is relatively cache coherency friendly
There seems to be a consensus on the third option and I guess that makes sense. But..

If the sub systems are the ones implementing the update/behaviors then are the components simply data holders? For some reason I still think behavior should be placed within the components, otherwise how else would you get different behaviors for components within the same subsystem?

I see these two options in terms of subsystems:



  1. [color="#1C2837"]Sub system only processes special information (such as update order) and component does the real logic (move, render). In this case, sub system should be quite simple and more like a container while component is complex.
  2. [color="#1C2837"]Component only holds data, no code, no logic, sub system handles all logic.

[/quote]

[color="#1c2837"]In the case of #1 you would still require a virtual Update() for the components to allow each component to implement different behaviors, which would undo the cache coherency advantage correct?
[color="#1c2837"]
[color="#1c2837"]How does a HealthComponent fit into this, or any other non-engine sub system related component? This is where it gets a bit confusing as the sub system approach works nicely when dealing with things like Physics, AI, and Rendering but for basic things like health, ammo, position/transform it seems not so nice.
[color="#1c2837"]
[color="#1c2837"]Your thoughts?
For me, components are data-only. They can also be queried to get their type, which is an enum. Each subsystem may handle different types differently. So an input system may process PlayerInputComponents by querying input state, and AIInputComponents by running a script. Health and similar stuff I consider "game logic," and would handle in a game logic system. Position/transform data seems best handled by a physics system to me.
How about,

1, A component belongs to one and only one sub system.
E.g, a render component does belong to render sub system.

2, The sub system updates all components.

3, The component itself doesn't know how to update. That's to say, no update logic in it.

Then the component can be data only or not, but it doesn't contain any complex update logic.

https://www.kbasm.com -- My personal website

https://github.com/wqking/eventpp  eventpp -- C++ library for event dispatcher and callback list

https://github.com/cpgf/cpgf  cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.


How about,

1, A component belongs to one and only one sub system.
E.g, a render component does belong to render sub system.
...

If "belonging" means that the mentioned sub-system is responsible for the kind of component, e.g. its update process, then okay. But particular components need to be used by more than a single sub-system for sure.


...
2, The sub system updates all components.

3, The component itself doesn't know how to update. That's to say, no update logic in it.

Then the component can be data only or not, but it doesn't contain any complex update logic.

Yes, but only if the behavior (and all belonging additional data) is at least stored as data inside components and interpreted by a sub-system. I'm thinking of the sub-system SpatialServices which is responsible to manage the placement (essentially a co-ordinate frame, in the end nothing more than the world matrices if you want so), bboxes and the like. Updating the placement is not the same for each and every model. The placement of static geometry isn't updated at all. Parented placements are updated due to updates of the parental frame or changes to the local frame. Notice that the local frame is additional data necessary to run the update process of parented placements. I have a dozen or so types of other update kinds, up to the grabbing of utensils utilizing a Grab frame (i.e. the hand that holds the utensil) and a Grip (i.e. the handle where and how the utensil is hold). These examples should make clear that the supporting data may be very different, and the overall structure is hence not so homogeneous.

This can be managed by differing between data components and behavior components, similar to variables and code. In such a configuration the sub-system is responsible for the update process as a whole, but may let the behaviors do the actual work. This would mean that behavior components supplement the sub-system's update process by providing a virtual function. It is also possible that the behaviors are just instructions (as a special kind of data) which would be interpreted by the sub-system.




How does a HealthComponent fit into this, or any other non-engine sub system related component? This is where it gets a bit confusing as the sub system approach works nicely when dealing with things like Physics, AI, and Rendering but for basic things like health, ammo, position/transform it seems not so nice.

I avoid having specific components like a HealthComponent if possible. The game mechanic may have an unforeseeable need for various components of such nature. Instead, I try to manage with general components like e.g. NumericStatComponent with a default value and limits and such. Binding such components is done by name. (Until now it is sufficient, but the tests so far weren't complex enough to guarantee that it will work in all cases.)

This topic is closed to new replies.

Advertisement