25
\$\begingroup\$

I've been working on some hobby projects the last 3-4 years. Just simple 2d and 3d games. But lately I have started a bigger project. Soo in the last couple of months I've been trying to design a game object class which can be the base of all my game objects. So after much try & die testing I turned to Google which quickly pointed me to some GDC PDFs and PowerPoints. And now I'm trying to get the grasp of component-based game objects.

I understand that the engine creates a game object and then attaches different components which handles things like health, physics, networking and whatever you make them do. But what I don't understand is how component X knows if Y has changed the state of the object. Like how does the PhysicsComponent know if the player is alive, because the health is controlled by the HealthComponent..? And how does the HealthComponent play the "player-died-animation"?

I was under the impression that it was something like this(In the HealthComponent):

if(Health < 0) {
   AnimationComponent.PlayAnimation("played-died-animation")
}

But then again, how does the HealthComponent know that the game object it is attached to have a AnimationComponent attached? The only solution I see here is

  1. Have a check to see if a AnimationComponent is attached or not (Either inside the component code or on the engine side)

  2. Have components require other components, but that seems to fight the whole component-design.

  3. Write like, HealthWithAnimationComponent, HealthNoAnimationComponent, and soo on, which again seems to fight the whole component-design idea.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Love the question. I should have asked the same months ago, but never got around to it. An additional problem I have faced is when a game object has multiple instance of the same component (multiple animations for example). It would be great if the answers could touch on that. I ended up using messages for notifications, with variables shared between all the components of a Game object (so they don't need to send a message to get a value for a variable). \$\endgroup\$
    – ADB
    Commented Jan 23, 2012 at 18:16
  • 1
    \$\begingroup\$ Depending on type of game, you probably wont have game objects that have health component and no animation component. And all these gameobjects are probably representation of something like Unit. So you can throw out the health component, and create UnitComponent that would have field health, and knew about all component the unit needs to be. This granularity of components doesnt really help anything - its more realistic to have one component per domain (rendering, audio, physics, game-logic). \$\endgroup\$
    – Kikaimaru
    Commented May 9, 2013 at 7:48

4 Answers 4

12
\$\begingroup\$

In all of your examples, there is a terrible problem. The health component needs to know about every component type that might need to respond to the entity dieing. Therefore, none of your scenarios are appropriate. Your entity has a health component. It has an animation component. Neither depend on or know about the other. They communicate through a messaging system.

When the health component detects that the entity has 'died', it sends an 'I died' message. It is the responsibility of the animation component to respond to this message by playing the appropriate animation.

The health component doesn't send the message directly to the animation component. Maybe it broadcasts it to every component in that entity, maybe to the entire system; maybe the animation component needs to let the messaging system know that it's interested in 'I died' messages. There are many ways to implement the messaging system. However you implement it, the point is that the health component and the animation component never need to know or care if the other is present, and adding new components will never require modifying existing ones to send them appropriate messages.

\$\endgroup\$
3
  • \$\begingroup\$ Okey, this makes sense. But who declares the "states" like 'dead', or 'portal-is-broken', etc. The component or the engine? Because adding a state 'dead' to a thing that is never going to have the healthcomponent attached seems kinda waste to me. I guess I'll just dive in and start to test some code and see what works. \$\endgroup\$
    – hayer
    Commented Jan 20, 2012 at 0:46
  • \$\begingroup\$ Michael and Patrick Hughes have the right answer above. Components are just data; so it's not really the health component that detects when the entity has died and sends the message, it's some higher level piece of game-specific logic. How to abstract that is up to you. The actual state of death never needs to be stored anywhere. The object is dead if it's health is < 0, and the health component can encapsulate that bit of data-checking logic without breaking a 'no behavior!' restriction if you consider only things that modify the state of the component as behavior. \$\endgroup\$
    – Blecki
    Commented Jan 20, 2012 at 13:40
  • \$\begingroup\$ Just curious, how would you handle a MovementComponent? When it detects input, it needs to increase the velocity in the PositionComponent. What would the message look like? \$\endgroup\$
    – Tips48
    Commented Aug 3, 2014 at 3:45
8
\$\begingroup\$

The way that Artemis solves the problem is to not do processing within Components. Components contain only the data they need. Systems read multiple component types and do whatever processing is necessary.

So, in your case, you may have a RenderSystem that reads in the HealthComponent (and others) and plays the queues up the appropriate animations. Separating data from functions this way makes it easier to keep dependencies properly managed.

\$\endgroup\$
5
  • \$\begingroup\$ This ends up being a nice way to handle the problem: Components represent properties while Systems tie together disparate properties and use those to do work. It's a huge shift away from traditional OOP thinking and makes some people's heads hurt =) \$\endgroup\$ Commented Jan 19, 2012 at 21:04
  • \$\begingroup\$ Okey, now I'm really lost.. "By contrast, in an ES, if you have 100 units on a battlefield, each represented by an Entity, then you have zero copies of each method that can be invoked on a unit – because Entities do not contain methods. Nor do Components contain methods. Instead, you have an external system for each aspect, and that external system contains all the methods that can be invoked on any Entity that possess the Component that marks it as being compatible with this system." Well, where is data in a GunComponent stored? Like rounds, etc. If all entities share the same component. \$\endgroup\$
    – hayer
    Commented Jan 20, 2012 at 1:27
  • 1
    \$\begingroup\$ As far as I understand it all entities do not share the same component, each entity can have N component instances attached to them. A System then queries the game for a list of all entities that have component instances they care about attached to them and then does whatever processing on those \$\endgroup\$
    – Jake Woods
    Commented Jan 20, 2012 at 5:08
  • \$\begingroup\$ This just moves the problem around. How does a system knows which components to use? A system could need other systems as well (the StateMachine system might want to call for an animation for example). However, it does solve the problem of WHO owns the data. In fact, a simpler implementation would be to have a dictionary in the game object and each system creates his variables in there. \$\endgroup\$
    – ADB
    Commented Jan 23, 2012 at 18:14
  • \$\begingroup\$ It does move the problem around but to a place that is more tenable. Systems have their relevant components hard wired. Systems can communicate to one another through Components (StateMachine can set a component value that Animation reads in to know what to do (or it could fire an Event). The dictionary approach sounds like the Properties Pattern which can also work. The nice thing about Components is that related properties are grouped together and they can be statically checked. No bizarre errors because you added "Dammage" in one place but tried to retrieve it using "Damage" in another. \$\endgroup\$
    – Michael
    Commented Jan 23, 2012 at 20:20
6
\$\begingroup\$

In your code you can there are to ways(I used them, possibly some other ways exist) to know if object changed state:

  1. Send message.
  2. Read directly data from component.

1) Have a check to see if a AnimationComponent is attached or not(Either inside the component code or on the engine side)

For this I used, 1. HasComponent function of GameObject, or 2. when you attach component you can check dependencies in some constructing function, or 3. If I know for sure that object has this component, I just use it.

2) Have components require other components, but that seems to fight the whole component-design.

In some articles I've read, that in Ideal system components do not depend on each other, but in real life it is not so.

3) Write like, HealthWithAnimationComponent, HealthNoAnimationComponent, and soo on, which again seems to fight the whole component-design idea.

It's a bad ide to write such components. In my app I created Health component most independent. Now I am thinking about some Observer pattern that notifies subscribers about some specific event(e.g. "hit", "heal" etc). So AnimationComponent must decide by itself when to play animation.

But when I've read article about CBES it impressed me, so I am very happy now when I use CBES and discover new possibilities of it.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Well, google.no/… @ slide 16 \$\endgroup\$
    – hayer
    Commented Jan 19, 2012 at 9:31
  • \$\begingroup\$ @bobenko, please give a link to article about CBES. I am very interesting in it, too;) \$\endgroup\$
    – Edward83
    Commented Jan 19, 2012 at 9:32
  • 1
    \$\begingroup\$ And lambdor.net/?p=171 @ bottom, this kinda of a summary of my question How can different functionality be defined in terms of relative complex, non-elementary components? What are the most elementary components? In which way are elementary components different from pure functions? How can existing components automatically communicate with new messages from new components? What is the point of ignoring a message that a component doesn’t know of? What happened to the input-process-output model after all? \$\endgroup\$
    – hayer
    Commented Jan 19, 2012 at 9:39
  • 1
    \$\begingroup\$ here is good answer on CBES stackoverflow.com/a/3495647/903195 most of articles I've researched are from this answer. I started and inspired with cowboyprogramming.com/2007/01/05/evolve-your-heirachy then In Gems 5(as I remember) there was good article with examples. \$\endgroup\$
    – Yevhen
    Commented Jan 19, 2012 at 9:45
  • \$\begingroup\$ But what about another concept functional-reactive programming, for me this question is still open, but may be for you is a good direction for researches. \$\endgroup\$
    – Yevhen
    Commented Jan 19, 2012 at 9:49
3
\$\begingroup\$

Its like Michael, Patrick Hughes and Blecki says. The solution to avoiding simply moving the problem around is to abandon the ideology that causes the problem in the first place.

Its less OOD and more like Functional Programming. When I started experimenting with Component-Based Design, I spotted this issue down the road. I googled some more, and I found "Functive Reactive Programming" as being the solution.

Now my components are nothing but a collection of variables and fields that describe its current state. Then I have a bunch of "System" classes that update all components that are relevant to them. The reactive part is achieved by running the Systems in a well defined order. This ensures that whatever System is next in line to do its processing and updating, and whatever components and entities it intends to read and update, its always working on up-to-date data.

However, in a way you could still claim that the problem has moved yet again, though. Because what if its not straighforward which order your Systems need to run in? What if there are cyclical relationships and its only a matter of time before you're staring at a mess of if-else and switch statements? Its an implicit form of messaging, no? At first glance, I think its a small risk. Usually, things are processed in order. Something like: Player Input -> Entity Positions -> Collision Detection -> Game Logic -> Rendering -> Start over. In that case, you'd have one System for each, provide each System with an update() method, and then run them in sequence in your gameloop.

\$\endgroup\$

You must log in to answer this question.

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