15
\$\begingroup\$

I'm trying to get my head around component based entity design.

My first step was to create various components that could be added to an object. For every component type i had a manager, which would call every component's update function, passing in things like keyboard state etc. as required.

The next thing i did was remove the object, and just have each component with an Id. So an object is defined by components having the same Ids.

Now, i'm thinking that i don't need a manager for all my components, for example i have a SizeComponent, which just has a Size property). As a result the SizeComponent doesn't have an update method, and the manager's update method does nothing.

My first thought was to have an ObjectProperty class which components could query, instead of having them as properties of components. So an object would have a number of ObjectProperty and ObjectComponent. Components would have update logic that queries the object for properties. The manager would manage calling the component's update method.

This seems like over-engineering to me, but i don't think i can get rid of the components, because i need a way for the managers to know what objects need what component logic to run (otherwise i'd just remove the component completely and push its update logic into the manager).

  1. Is this (having ObjectProperty, ObjectComponent and ComponentManager classes) over-engineering?
  2. What would be a good alternative?
\$\endgroup\$
7
  • 1
    \$\begingroup\$ You have the right idea by trying to learn the component model, but you need to get a better understanding of what it needs to do - and the only way to do that is to [mostly] complete a game without using it. I think making a SizeComponent is overkill - you can assume that most objects have a size - it's things like rendering, AI and physics where the component model is used; Size will always behave the same - so you can share that code. \$\endgroup\$ Nov 16, 2011 at 11:03
  • \$\begingroup\$ Related: gamedev.stackexchange.com/questions/14607/… \$\endgroup\$
    – Den
    Nov 16, 2011 at 11:37
  • \$\begingroup\$ @JonathanDickinson, @Den: I think, then my problem is where do i store common properties. E.g. an object as a postion, which is used by a RenderingComponent and a PhysicsComponent. Am i over-thinking the decision of where to put the property? Should i just stick it in either, then have the other query an object for the component that has the needed property? \$\endgroup\$ Nov 16, 2011 at 11:57
  • \$\begingroup\$ My previous comment, and thought process behind it is what's driving me to have a separate class for a property (or group of related properties maybe) that components can query. \$\endgroup\$ Nov 16, 2011 at 11:58
  • 1
    \$\begingroup\$ I really like that idea - it might be worth trying; but having an object to describe each individual property is really expensive. You could try PhysicalStateInstance (one per object) alongside a GravityPhysicsShared (one per game); however I am tempted to say this is venturing into the realms of architects euphoria, don't architect yourself into a hole (exactly what I did with my first component system). KISS. \$\endgroup\$ Nov 16, 2011 at 12:16

6 Answers 6

6
\$\begingroup\$

The simple answer to your first question is Yes, you are over engineering the design. The 'How far do I break things down?' question is very common when the next step is taken and the central object (usually called an Entity) is removed.

When you are breaking down the objects to such a detailed level as to have size on its own then the design has gone too far. A data value on its own is not a component. It is a built in data type and can often be called exactly what you have started calling them, a property. A property is not a component, but a component does contain properties.

So, here are a few guide lines I try and follow when developing in a component system:

  • There is no spoon.
    • This is the step that you have already taken in getting rid of the central object. This removes the entire debate of what goes into the Entity object and what goes into a component as now all you have are the components.
  • Components are not structures
    • If you break something down to where it just contains data then it is not a component any longer, it is just a data structure.
    • A component should contain all the functionality needed to accomplish a very specific task in a specific manner.
    • The IRenderable interface provides the generic solution to visually display anything in the game. CRenderableSprite and CRenderableModel is a component implementation of that interface that provides the specifics to render in 2D and 3D respectively.
    • IUseable is the interface for something that a player is able to interact with. CUseableItem would be the component that either fires the active gun or drinks the selected potion whereas CUseableTrigger could be where a player goes to hop into a turret or throw a lever to drop the drawbridge.

So with the guideline of components not being structures, the SizeComponent has been broken down too far. It contains only data and what defines the size of something can vary. For example, in a rendering component it could be a 1d scalar or a 2/3d vector. In a physics component it could be the bounding volume of the object. In an inventory item it could be how much space it takes up on a 2D grid.

Try and draw a good line between theory and practicality.

Hope this helps.

\$\endgroup\$
12
  • \$\begingroup\$ Let's not forget that on some platforms, calling a function from an Interface is longer than calling one from a parent Class (since your answer included mentions of interfaces and classes) \$\endgroup\$
    – ADB
    Nov 21, 2011 at 18:27
  • \$\begingroup\$ Good point to remember, but I was trying to remain language agnostic and just using them in the general design terms. \$\endgroup\$
    – James
    Nov 21, 2011 at 18:49
  • \$\begingroup\$ "If you break something down to where it just contains data then it is not a component any longer, it is just a data structure." -- Why? "Component" is such a generic word that it can mean data structure as well. \$\endgroup\$
    – Paul Manta
    Jan 2, 2012 at 20:23
  • \$\begingroup\$ @PaulManta Yes it is a generic term, but the entire point of this question and answer is where to draw the line. My answer, as you quoted, is just my suggestion for a rule of thumb to do just that. As always I advocate never letting theory or design considerations be what drives development, its meant to assist it. \$\endgroup\$
    – James
    Jan 2, 2012 at 23:12
  • 1
    \$\begingroup\$ @James That was an interesting discussion. :) chat.stackexchange.com/rooms/2175 My biggest gripe if your implementation is that components know too much about what other components are interested in. I'd like to continue the discussion at a future time. \$\endgroup\$
    – Paul Manta
    Jan 9, 2012 at 21:15
14
\$\begingroup\$

You already accepted an answer, but here's my stab at a CBS. I found that a generic Component class has some limitations, so I went with a design described by Radical Entertainment at GDC 2009, who suggested separating components into Attributes and Behaviors. ("Theory and Practice of the Game Object Component Architecture", Marcin Chady)

I explain my design decisions in a two page document. I'll just post the link since it's too long to paste it all here. It currently only covers the logic components (not the rendering and physics components as well), but it should give you an idea of what I tried to do:

http://www.pdf-archive.com/2012/01/08/entity-component-system/preview/page/1

Here's an excerpt from the document:

Attributes and Behaviors in Short

Attributes manage one category of data and any logic they have is limited in scope. For example, Health might make sure that its current value is never greater than its maximum value, and it can even notify other components when the current value drops below a certain critical level, but it does not contain any more complex logic. Attributes are dependent on no other Attributes or Behaviors.

Behaviors control how the entity reacts to game events, make decisions, and alter the values of Attributes as needed. Behaviors are dependent on some of the Attributes, but they cannot directly interact with each other – they only react to how Attributes’ values are changed by the other Behaviors and to the events they are sent.


Edit: And here's a relationship diagram that shows how the components communicate with each other:

Communication diagram between Attributes and Behaviors

An implementation detail: the entity-level EventManager is only created if it is used. The Entity class just stores a pointer to an EventManager that is initialized only if some component requests it.


Edit: On another question I gave a similar answer to this one. You can find it here for a, perhaps, better explanation of the system:
https://gamedev.stackexchange.com/a/23759/6188

\$\endgroup\$
0
2
\$\begingroup\$

It really depends on the properties you need and where you need them. The amount of memory you will have and the processing power/type you will use. I have seen and try to do the following:

  • Properties that are used by multiple components but modified only by one are stored in that component. Shape is a good example in a game where the AI system, the physics system as well as the rendering system need access to the base shape, it's a heavy property and it should remain only in one place if possible.
  • Properties like position sometimes need to be duplicated. For example if you run multiple systems in parallel you want to avoid peeking across systems and will rather sync the position (copy from the master component or sync through deltas or with a collision pass if needed).
  • Properties originating from controls or AI "intentions" can be stored in a dedicated system as they can be applied to the other systems without being visible from outside.
  • Simple properties can become complicated. Sometimes your position will require a dedicated system if you need to share a lot of data (position, orientation, frame delta, total delta current movement, delta movement for the current frame and for the previous frame, rotation...). In that case you will have to go with the system and access the latest data from the dedicated component and you might have to change it through accumulators (deltas).
  • Sometimes your properties can be stored in a raw array (double*) and your components will simply have pointers to the arrays holding the different properties. The most obvious example is when you need massive parallel calculations (CUDA, OpenCL). So having one system to properly manage the pointers might come in handful.

These principles have their limitations. Of course you will have to push the geometry to the renderer but you will probably not want to retrieve it from there. The master geometry will be stored in the physics engine in the case where deformations occur there and synced with the renderer (from time to time depending on the distance of the objects). So in a way you will duplicate it anyway.

There are no perfect systems. And some games will be better off with a simpler system while other will require more complex synchronizations across systems.

At first make sure all properties can be accessed in a simple manner from your components so you can change the way you store the properties transparently once you start fine-tuning your systems.

There is no shame in copying some properties. If a few components need to hold a local copy it's sometimes more efficient to copy and sync rather than access an "external" value"

Also syncing doesn't have to happen every frame. Some components can be synced less frequently than others. Render component are often a good example. The ones not interacting with the players can be synced less frequently, just as the ones that are far away. Those far and outside of the camera field can be synced even less frequently.


When it comes to your size component it could probably be bundled within your position component:

  • not all entities with a size have a physics component, areas for example, so bundling it with physics is not in your best interest.
  • size will probably not matter without a position
  • all objects with a position will probably have a size (that can be used for scripts, physics, AI, render...).
  • the size is probably not updated every cycle but position might be.

Instead of size you could even use a size modifier, it might come in handier.

As to storing all properties in a generic property storage system... I am not sure you are going in the right direction... Focus on the properties that are core to your game and create components that bundle as many related properties as possible. As long as you abstract the access to these properties properly (through getters in the components that need them for example) you should be able to move, copy and sync them later, without breaking too much of the logics.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ BTW +1 or -1 me because my current rep is 666 since the 9th of november... It's creepy. \$\endgroup\$
    – Coyote
    Nov 16, 2011 at 16:52
1
\$\begingroup\$

If components can be arbitrarily added to entities, then you need a way to query if a given component exists in an entity and to get a reference to it. So you might iterate over a list of objects derived from ObjectComponent until you find the one you want, and return it. But you would return an object of the correct type.

In C++ or C# this usually means you'd have a template method on the entity like T GetComponent<T>(). And once you have that reference, you know exactly what member data it holds, so just access it directly.

In something like Lua or Python you don't necessarily have an explicit type of that object, and probably don't care either. But again, you can just access the member variable and handle any exception that arises from attempting to access something that isn't there.

Querying for object properties explicitly sounds like duplicating the work that the language can do for you, either at compile time for statically-typed languages or at run time for dynamically typed ones.

\$\endgroup\$
2
  • \$\begingroup\$ I understand about getting strongly-typed components from an entity (using generics or such), my question is more about where those properties should go, particularly where a property is used by multiple components and no single component can be said to own it. See my 3rd and 4th comment on the question. \$\endgroup\$ Nov 16, 2011 at 12:45
  • \$\begingroup\$ Just pick an existing one if it fits, or factor the property into a new component if it doesn't. For example Unity has a 'Transform' component which is just the position, and if anything else needs to alter the object's position, they do it via that component. \$\endgroup\$
    – Kylotan
    Nov 16, 2011 at 17:45
1
\$\begingroup\$

"I think, then my problem is where do i store common properties. E.g. an object as a postion, which is used by a RenderingComponent and a PhysicsComponent. Am i over-thinking the decision of where to put the property? Should i just stick it in either, then have the other query an object for the component that has the needed property?"

The thing is that RenderingComponent uses position, but the PhysicsComponent provides it. You just need a way to tell each user component which provider to use. Ideally in an agnostic way, otherwise there will be a dependency.

"...my question is more about where those properties should go, particularly where a property is used by multiple components and no single component can be said to own it. See my 3rd and 4th comment on the question."

There is no common rule. Depends on specific property (see above).

Make a game with an ugly but component-based architecture and then refactor it.

\$\endgroup\$
3
  • \$\begingroup\$ I don't think i quite understand what PhysicsComponent should do then. I see it as managing simulating the object within a physical environment, which leads me to this confusion: Not all things that need to be rendered will need to be simulated, so it seems wrong for me to add PhysicsComponent when i add RenderingComponent because it contains a position that RenderingComponent uses. I could easily see myself ending up with a web of inter-connected components, meaning all/most need to be added to each entity. \$\endgroup\$ Nov 16, 2011 at 13:31
  • \$\begingroup\$ I had a similar situation actually :). I have a PhysicsBodyComponent and a SimpleSpatialComponent. Both of them provide Position, Angle and Size. But the first one participates in physics simulation and has additional relevant properties, and second one just holds that spatial data. If you have your own phys engine you can even inherit the former from the latter. \$\endgroup\$
    – Den
    Nov 16, 2011 at 14:24
  • \$\begingroup\$ "I could easily see myself ending up with a web of inter-connected components, meaning all/most need to be added to each entity." That's because you don't have an actual game prototype. We are talking about some basic components here. No wonder they will be used everywhere. \$\endgroup\$
    – Den
    Nov 16, 2011 at 14:34
1
\$\begingroup\$

Your gut's telling you that having the ThingProperty, ThingComponent, and ThingManager for every Thing type of component a little overkill. I think it's right.

But, you need some way to keep track of related components in terms of what systems use them, what entity they belong to, etc.

TransformProperty is gonna be a pretty common one. But who's in charge of it, the rendering system? The physics system? The sound system? Why would a Transform component even need to update itself?

The solution is to remove any sort of code from your properties outside of getters, setters, and initializers. Components are data, which is used by systems in the game to perform various tasks like rendering, AI, sound playback, movement, etc.

Read about Artemis: http://piemaster.net/2011/07/entity-component-artemis/

Look at its code and you'll see that it's based around Systems that declare their dependencies as lists of ComponentTypes. You write each of your System classes and in the constructor/init method declare what types that system depends on.

During setup for levels or whatnot, you create your entities and add components to them. Afterwards you tell that entity to report back to Artemis, and Artemis then figures out based on the composition of that entity which systems would be interested in knowing about that entity.

Then during the update phase of your loop, your Systems now have a list of what entities to update. Now you can have granularity of components so you can devise crazy systems, build entities out of a ModelComponent, TransformComponent, FliesLikeSupermanComponent, and SocketInfoComponent, and do something weird like make a flying saucer that flies between clients connected to a multiplayer game. Okay, maybe not that, but the idea is that it keeps things decoupled and flexible.

Artemis isn't perfect, and the examples on the site are a little basic, but the separation of code and data is powerful. It's also good for your cache if you do it right. Artemis probably doesn't do it right on that front, but it's good to learn from.

\$\endgroup\$
0

You must log in to answer this question.

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