Component based game and component communication

Started by
31 comments, last by Scourage 10 years, 2 months ago

Hello,

I want to use a component based system in my game. It should have subsystems for logic, and every subsystem has a list of components which stores the data.

The problem is: How to sync the components?

  • Should I have a pointer to another component (Movement subsystem needs position of entity, so its component has a pointer to the position component?)
  • Should I go with a observer pattern, which notifies all other (registered) subsystems, that the position of the entity has changed? Then I need a reference from the movement subsystem to the position subsystem, to get the actual position, because with the notify I only want that the notified subsystem adds a "to-be-processed" entry to it's queue. This should avoid a confuse processing of the entities.

Are there other (better?) approaches?

Thank you for your tips!

Advertisement

Hi!

Im not sure of how your current setup is working, and what a "subsystem" is, but in general a system should act on an entity with one or more component.

For instance, the MovementSystem could move an entity that has a displacement and velocitty component, the RenderSystem could render an entity that has a displacement and appearance component etc. This way the system needs to know about certain components, but the components does not need to know about each other.

Look here: http://www.gamedev.net/page/resources/_/technical/game-programming/implementing-component-entity-systems-r3382

In some cases I guess components will need to know about each other, I do not have that need yet, so I can not offer you a good answer.

I do however think you should implement some sort of messaging system.

Look here: http://www.gamedev.net/page/resources/_/technical/game-programming/case-study-bomberman-mechanics-in-an-entity-component-system-r3159

Good luck =)


1) Should I have a pointer to another component (Movement subsystem needs position of entity, so its component has a pointer to the position component?)
2) Should I go with a observer pattern, which notifies all other (registered) subsystems, that the position of the entity has changed? Then I need a reference from the movement subsystem to the position subsystem, to get the actual position, because with the notify I only want that the notified subsystem adds a "to-be-processed" entry to it's queue. This should avoid a confuse processing of the entities.

Those two bullets seem like solutions to different problems:

1) How do I get component X for an entity, given I have component Y for that entity

2) You have code that needs to know when position has changed, how do you set that up?

Can you clarify your question?

For (2), I would ask, do you really need this?

hello.

There should be no right or wrong way to do this as long as the out come is the same.

In my carry Object Component I have a owner pointer.

this way when I update the carryobjectcom it calls the owner objects virtual functions for Getpos, size and things

to pick up a object this way the component can do its job and not worry about what values it need to control as the owner does all that with its other components

you just need a common interface for functions the components need to use to do there job.

So for my carry objects componet it can move the object to the unit it wants to pick up and when it gets to the target it picks it up.

The architecture works like sneftel wrote in this thread:

http://www.gamedev.net/topic/463508-outboard-component-based-entity-system-architecture/

Given I have a physics system, a translation system and a position system. The component which stores the position is the position component linked to the position system. My physic and translation system have to change the position component.

It seems to me, that there are two ways:

I can store the position in a vector in the translation component and physics component also, and implement a observer system, to sync, when the position is updated, every other component. (The translation system changes the position -> updates the position component over the position system -> the position component notifies all listeners, to sync the position) That means, that my translation system stores a pointer to the position system, to update the position.

I can store a pointer to the position component in every component I need it. That means that I also need a pointer to the position system, to get a pointer to the position component. So I don't need to sync the components manually, but my components depends on other, which I don't like.

I like way one a little bit more, because I have dependencies only on system level. But maybe there are other ways to do this.

phil_t wrote another way, in which he has a sync primitive, which stores two components and after every frame update, updates the position over this primitive.

There are much ways to do this, but maybe there are other pros and cons in my ways, which I don't see.

For a moment take a step back from having a straight look at the components, and take a look at the game loop. It has a structure oriented on tasks: Processing input, a first animation pass, physics, collision resolution, perhaps a second animation pass, and rendering at last (more or less; details are not important here). Notice that the tasks are based on top level sub-systems, and depend on components managed by probably lower level sub-systems.

Looking at the rendering sub-system, does it need to be notified about position changes done in any of the animation, physics, or collision tasks? No! At the moment of rendering, the sub-system can safely assume that any and all positions and orientations (i.e. the entire placement) are settled and well defined, because beforehand running sub-systems have done their jobs. Any notification of a "RenderComponent" (I use it here for clarification; I'm not a fan of RenderComponent at all) done before would be a waste.

Looking at the collision sub-system, does it need to be notified about position changes? No! Because collision detection is a self-contained process, running in its entirety but not on request on every little move.

Of course, having an explicit motion sub-system (or using the animation sub-system) requires a way that the sub-system can set the placement as needed. There need to be a reference from the animation sub-system to a placement component (which is probably managed in another sub-system). But there is neither a need for an animation component (whatever it means exactly) to refer to the placement, nor for the placement component to notify the animation (component or sub-system).

In summary I mean that in consideration of all the discussion of linking, messaging, slots and whatnot, one should in the first place think whether notification in each particular case is needed at all. The use of sub-systems allows for concentrated and perhaps in order processing, and that does not work well if the program jumps forth and back in code. Concentration may be yielded in by letting one and the same sub-system handle different but related components, too. (All this does not exclude that in some cases notification may be meaningful.)

Ok you mean, that one system (for example physics system) knows it's dependency to the position system, and every update the first thing it does, is requesting the position. So there is no need for manually syncing.

But one question remains, how to store position in the physics component, or is this not needed? I don't want to store a vector in the physics component also, because of duplicate data. A pointer is ok, but I think it breaks encapsulation, because one component needs to know one other...


But one question remains, how to store position in the physics component, or is this not needed? I don't want to store a vector in the physics component also, because of duplicate data. A pointer is ok, but I think it breaks encapsulation, because one component needs to know one other...

A wise man avoids to commit self and says … "it depends" ;)

Notice that using an external physics library may require you to copy the placement anyway, and that in both directions. An internal physics solution may read the placement from the spatial sub-system piece by piece on demand, or it may read it in a block and bring it into a format required for an efficient processing (w.r.t. physics). However it is done, the physics system should be able to pull the data (data should IMHO not need to be pushed into the physics sub-system).

Well, instead of duplicating components, just extract them by splitting the storage from the systems.

Add some helper template class (component-manager/array/vector/storage/..., whatever you like to call it) that keeps one kind of components and gives search/addition/deletion by id and easy access through iterators.

Then give each system a reference to one or if needed two or more of these.

Then let the systems one after another in a fixed order do their update-work so that they can rely on other systems to have done what was needed before.

I think if you want to send data between components, you should have them an anchor to a common root which actually handles sending the information between components.

For example, in my game, I have components bound to individual entities which gives them functionality. I also have some specialized components such as an InputComponent and a RenderComponent. Each component haves a pointer back to it's root entity and my entity has a function called BroadCastMessage( MessageClass data ) which calls the function RecieveMessage( MessageClass data ) for all bound components. All my component has to do is use it's pointer to its root entities to broadcast a message to other components.

My MessageClass is basically this:


struct MessageClass
{
   char* pchName;
   void* pvData;
}

You would use the name to listen for certain events from other components like maybe "UpdateXPos" or something to that effect. Also since I know how a message would be built based on the name, I'll know how to typecast the data to its correct format. Another way you might do it, but it leads to a bit more work, is to use an array of bytes for the data. You would have to break down the data you need to send into individual bytes and then rebuild it up when a component receives it.

EDIT
Here's a complete example:


//InputComponent
void KeyPressed( char chKey )
{
   if( chKey == 'w' )
   {
      int iMovement = 10;
      pEntity->BroadcastMessage( MessageClass( "UpdateXPos", &iMovement );
   }
}

//RenderComponent
void RecieveMessage( MessageClass data )
{
   if( strcmp( data.pchName, "UpdateXPos" ) == 0 )
   {
      m_iPosX += *((int*)data.pvData);
   }
}

This topic is closed to new replies.

Advertisement