10
\$\begingroup\$

Instead of my usual inheritance heavy game engines I'm toying with a more component based approach. However I have a hard time justifying where to let the components do their thing.

Say I have a simple entity that has a list of components. Of course the entity does not know what these components are. There might be a component present that gives the entity a position on screen, another one might be there to draw the entity on screen.

In order for these components to work they have to updated every frame, the easiest way to do this is to walk over the scene tree and then for each entity update each component. But some components might need a little bit more management. For example a component that makes an entity collidable must be managed by something that can oversee all collidable components. A component that makes an entity drawable needs someone to oversee all other drawable components to figure out the draw order, etc...

So my question is, where do I update the components, what is a clean way of getting them to the managers?

I have thought about using a singleton manager object for each of the components types but that has the usual drawbacks of using a singleton, a way to alleviate this is a bit is by using dependency injection but that sounds like overkill for this problem. I could also walk over the scene tree and then gather the different components into lists using some sort of observer pattern but that seems a bit wasteful to do every frame.

\$\endgroup\$
9
  • 1
    \$\begingroup\$ Are you using systems in some way? \$\endgroup\$
    – Asakeron
    Feb 8, 2013 at 12:32
  • \$\begingroup\$ Component systems are the usual way to do this. I personally just call update on all entities, which calls update on all components, and have a few "special" cases (like spatial manager for collision detection, which is static). \$\endgroup\$
    – ashes999
    Feb 8, 2013 at 13:05
  • \$\begingroup\$ Component systems? I never heard of those before. I'll start Googling, but I would welcome any recommended links. \$\endgroup\$
    – Roy T.
    Feb 8, 2013 at 13:06
  • 1
    \$\begingroup\$ Entity Systems are the future of MMOG development is a great resource. And, to be honest I am always confused by these architecture names. The difference with the suggested approach is that components only hold data and systems proccess it. This answer is very relevant as well. \$\endgroup\$
    – Asakeron
    Feb 8, 2013 at 13:41
  • 1
    \$\begingroup\$ I wrote a kind-of-meandering blog post on this subject here: gamedevrubberduck.wordpress.com/2012/12/26/… \$\endgroup\$
    – Alex
    Feb 14, 2013 at 13:11

2 Answers 2

15
\$\begingroup\$

I would suggest starting by reading Mike Acton's 3 big lies, because you violate two of them. I'm serious, this will change the way you design your code: http://cellperformance.beyond3d.com/articles/2008/03/three-big-lies.html

So which do you violate?

Lie #3 - Code is more important than data

You talk about dependency injection, which may be useful in some (and only some) instances but should always ring a great big alarm bell if you use it, especially in game development! Why? Because it is an often unnecessary abstraction. And abstractions in the wrong places are horrible. So you have a game. The game has managers for different components. The components are all defined. So make a class somewhere in your main game loop code that "has" the managers. Like:

private CollissionManager _collissionManager;
private BulletManager _bulletManager;

Give it some getter functions to get each manager class (getBulletManager()). Maybe this class itself is a Singleton or it is reachable from one (you've probably got a central Game singleton somewhere anyway). There's nothing wrong with well defined hard-coded data and behavior.

Don't make a ManagerManager which lets you register Managers using a key, which can be retrieved using that key by other classes that want to use the manager. It's a great system and very flexible, but where talking about a game here. You know exactly which systems are in the game. Why pretend like you don't? Because this is a system for people who think code is more important than data. They will say "The code is flexible, the data just fills it". But code is just data. The system I described is far easier, more reliable, easier to maintain and a lot more flexible (for instance, if the behavior of one manager differs from other managers, you only have to change a few lines instead of reworking the entire system)

Lie #2 - Code should be designed around a model of the world

So you have an entity in the game world. The entity has a number of components defining its behavior. So you make an Entity class with a list of Component objects, and an Update() function which calls the Update() function of each Component. Right?

Nope :) That's designing around a model of the world: you have bullet in your game, so you add a Bullet class. Then you update each Bullet and move on to the next one. This will absolutely kill your performance and it gives you a horrible convoluted codebase with duplicate code everywhere and no logical structuring of similar code. (Check out my answer here for a more in-detail explanation of why traditional OO design sucks, or look up Data Oriented Design)

Let's take a look at the situation without our OO bias. We want the following, no more no less (please note there's no requirement to make a class for entity or object):

  • You have a bunch of entities
  • Entities comprise of a number of components which define the entity's behavior
  • You want to update each component in the game each frame, preferably in a controlled way
  • Other than identifying components as belonging together, there is nothing the entity itself needs to do. It's a link/ID for a couple of components.

And let's look at the situation. Your component system will update the behavior of every object in the game every frame. This is definitely a critical system of your engine. Performance is important here!

If you're familiar with either computer architecture or Data Oriented Design, you know how the best performance is achieved: tightly packed memory and by grouping code execution. If you execute snippets of code A, B and C like this: ABCABCABC, you will not get the same performance as when you execute it like this: AAABBBCCC. This isn't just because the instruction and data cache will be used more efficiently, but also because if you execute all "A"s after one another, there is a lot of room for optimization: removing duplicate code, precalculate data that's used by all "A"s, etc.

So if we want to update all components, let's not make them classes/objects with an update function. Let's not call that update function for each component in each entity. That's the "ABCABCABC" solution. Let's group all identical component updates together. Then we can update all A-components, followed by B, etc. What do we need to make this?

First, we need Component Managers. For every type of component in the game, we need a manager class. It has an update function which will update all components of that type. It has a create function that will add a new component of that type and a remove function that will destroy the specified component. There may be other helper functions to get and set data specific to that component (eg: set the 3D model for Model Component). Note that the manager is in some ways a black box to the outside world. We don't know how data of each component is stored. We don't know how each component is updated. We don't care, as long as the components behave as they should.

Next we need an entity. You could make this a class, but that's hardly necessary. An entity could be nothing more than a unique integer ID or a hashed string (so also an integer). When you create a component for the Entity, you pass the ID as argument to the Manager. When you want to remove the component, you pass the ID again. There may be some advantages to adding a bit more data to the Entity instead of just making it an ID, but those will only be helper functions because as I've listed in the requirements, all entity behavior is defined by the components themselves. It's your engine though, so do what makes sense for you.

What we do need is an Entity Manager. This class will either generate unique IDs if you use the ID-only solution, or it can be used to create/manage Entity objects. It can also keep a list of all entities in the game if you need that. The Entity Manager could be the central class of your component system, storing the references to all the ComponentManagers in your game and calling their update functions in the right order. That way all the game loop has to do is call EntityManager.update() and the whole system is nicely separated from the rest of your engine.

That's the bird-eye view, let's take a look at how the component managers work. Here's what you need:

  • Create component data when create(entityID) is called
  • Delete component data when remove(entityID) is called
  • Update all (applicable) component data when update() is called (ie not all components need to update each frame)

The last one is where you define the components behavior/logic and depends completely on the type of component you're writing. The AnimationComponent will update the Animation data based on the frame it's at. The DragableComponent will update only a component that is being dragged by the mouse. The PhysicsComponent will update data in the physics system. Still, because you update all components of the same type in one go, you can do some optimizations that are not possible when each component is a separate object with an update function that could be called at any time.

Note that I've still never called for the creation of a XxxComponent class to hold component data. That's up to you. Do you like Data Oriented Design? Then structure the data in separate arrays for each variable. Do you like Object Oriented Design? (I wouldn't recommend it, it will still kill your performance in a lot of places) Then create a XxxComponent object that will hold the data of each component.

The great thing about the managers is encapsulation. Now encapsulation is one of the most horribly misused philosophies in the world of programming. This is how it should be used. Only the manager knows what component data is stored where, how a component's logic works. There are a few functions to get/set data but that's it. You could rewrite the entire manager and its underlying classes and if you don't change the public interface, no-one even notices. Changed physics engine? Just rewrite PhysicsComponentManager and you're done.

Then there's one final thing: communication and data sharing between components. Now this is tricky and there is no one-size-fits-all solution. You could create get/set functions in the managers to allow for instance the collision component to get the position from the position component (ie PositionManager.getPosition(entityID)). You could use an event system. You could store some shared data in entity (the ugliest solution in my opinion). You could use (this is often used) a messaging system. Or use a combination of multiple systems! I don't have the time or experience to go into each of these systems, but google and stackoverflow search are your friends.

\$\endgroup\$
6
  • \$\begingroup\$ I find this answer very interesting. Just one question (hope you or someone can respond to me). How do you manage to eliminate the entity on a DOD component-based system? Even Artemis use Entity as a class, i'm not sure that's very dod. \$\endgroup\$ Mar 20, 2013 at 7:57
  • 1
    \$\begingroup\$ What do you mean by eliminate it? Do you mean an entity system without an Entity class? The reason Artemis has an Entity is because in Artemis, the Entity class manages its own components. In the system I proposed, the ComponentManager classes manage the components. So instead of needing a Entity class, you can just have a unique integer ID. So let's say you have entity 254, which has a position component. When you want to change the position, you can call PositionCompMgr.setPosition(int id, Vector3 newPos), with 254 as the id parameter. \$\endgroup\$
    – Mart
    Mar 22, 2013 at 16:30
  • \$\begingroup\$ But how do you manage IDs? What if you want to remove a component from an entity to assign it later to other? What if you want to remove an entity and add a new one? What if you want one component to be shared between two or more entities? I'm really interest in this. \$\endgroup\$ Mar 24, 2013 at 7:15
  • 1
    \$\begingroup\$ EntityManager can be used to give out new IDs. It could also be used to create complete entities based on pre-defined templates (eg create "EnemyNinja" which generates a new ID and creates all components that make up an enemy ninja such as renderable, collission, AI, maybe some component for melee combat, etc). It can also have a removeEntity function which automatically calls all ComponentManager remove functions. The ComponentManager can check if it has component data for the given Entity and if so, delete that data. \$\endgroup\$
    – Mart
    Mar 29, 2013 at 17:15
  • 1
    \$\begingroup\$ Move a component from one entity to another? Just add a function swapComponentOwner(int oldEntity, int newEntity) to each ComponentManager. The data is all there in ComponentManager, all you need is a function to change which owner it belongs to. Each ComponentManager will have something like an index or map to store which data belongs to which entity ID. Just change the entity ID from the old to the new ID. I'm not sure if sharing components is easy in the system I thought up, but how hard can it be? Instead of one Entity ID<->Component Data link in the index table there are multiple. \$\endgroup\$
    – Mart
    Mar 29, 2013 at 17:20
3
\$\begingroup\$

In order for these components to work they have to updated every frame, the easiest way to do this is to walk over the scene tree and then for each entity update each component.

This is the typical naive approach to component updates (and there's nothing necessarily wrong with it being naive, if it works for you). One of the big problems it has you actually touched on -- you're operating through the interface of the component (for example IComponent) so you know nothing about what it is you just updated. You likely also don't know anything about the ordering of components within the entity, so

  1. you're likely to update components of differing types frequently (poor code locality of reference, essentially)
  2. this system doesn't lend itself well to concurrent updates because you aren't in a position to identify data dependencies and thus split out the updates into local groups of unrelated objects.

I have thought about using a singleton manager object for each of the components types but that has the usual drawbacks of using a singleton, a way to alleviate this is a bit is by using dependency injection but that sounds like overkill for this problem.

A singleton isn't really needed here, and so you should avoid it because it does carry the downsides you mentioned. Dependency injection isn't overkill -- the heart of the concept is that you pass things that an object needs to that object, ideally in the constructor. You don't need a heavyweight DI framework (like Ninject) for this -- just pass an extra parameter to a constructor somewhere.

A renderer is a fundamental system and it probably supports creating and managing the lifetime of a bunch of renderable objects that correspond to visual things in your game (sprites or models, likely). Similarly, a physics engine likely has lifetime control over things that represent the entities that can move around in the physics simulation (rigid bodies). Each of those relevant systems should own, in some capacity, those objects and be responsible for updating them.

The components you use in your game entity composition system should just be wrappers around the instances from those lower-level systems -- your position component could just wrap a rigid body, your visual component just wraps a renderable sprite or model, et cetera.

Then the system itself that owns the lower-level objects is responsible for updating them, and can do so in bulk and in a way that allows it to multithread that update if appropriate. Your main game loop controls the crude order in which those systems update (physics first, then renderer, or whatever). If you have a subsystem that doesn't have lifetime or update control over the instances it hands out, you can build a simple wrapper to handle the update of all the components relevant to that system in bulk as well, and decide where to place that update relative to the rest of your system updates (this often happens, I find, with "script" components).

This approach is occasionally known as the outboard component approach, if you're looking for more detail.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .