Entity System question

Started by
28 comments, last by Kylotan 15 years, 12 months ago
In my first post I forgot to mention that although your SubSystems create and receive events, there should still be a universal EventManager. When a SubSystem wants to send an event, it creates the event and gives it to the EventManager. The EventManager can then send the event to all the SubSystems who have registered themselves to receive events of that type. Once the SubSystems receive events from the EventManager they can handle it.

Quote:
Quote:
The individual components do not send the events, but they create them (e.g. Life component sees entity.Life = 0, so it creates an EntityDeadEvent) and then they give them to their parent SubSystem.


Actually I have no methods in the components (only getter and setters), so the component would not know by itself that it's dead. The LifeSubSystem would check if the child component is dead and then create the event. I don't see how a component can create an event on its own since there is no Update() method in the component.


If the LifeSubSystem checks its child components, that would require it to poll all of its child components every update. Depending on your specific game, that may be a poor way of handling the situation.

Perhaps in a setter method you could create an event if Life = 0. Something like this pseudocode:

class LifeComponent { private:  int Life; public:  void SetLife(int l){   Life = l;   // Check for Life = 0   if(Life == 0){    // Create event    // Note: Here's where you would include this components EntityID# and any other information you want    Event deadEvent(...)    // Give event to parent SubSystem    mySubSystem->sendEvent(deadEvent);  }


Your event system may depend on how you create your components. This may be an ugly way of creating events, or it may work out good for you.

Quote:
Quote:
When a SubSystem receives an event from another SubSystem (e.g. LifeSubSystem sends event to VisualEffectSubSystem) it could pass the event on to all of its child components who care to receive the event.


How does the SubSystem know which child components care about the event?


The child component will register themselves to receive events of a certain type. Perhaps the type could be of which SubSystem is sending the event. This registering could be done twice; the SubSystem registers with the EventManager, and the components register with the SubSystem. Keep in mind that it's not necessary to register yourself with anything, but you wouldn't receive any events. You could also have your SubSystem register for events while none of its child components are registered with the SubSystem. In this situation, you could have the SubSystem do whatever it wants; it could destroy some components or create some, or instead send a new event, all without the child components knowing of any such event.

Any class that cares about an event must inherit the EventListener interface. Then, registering for events is as easy as:

// VisualEffectSubSystem registering to receive events of type Life (i.e. from the LifeSubSystem)
EventManager->registerListener(this, EventType::Life);


Quote:
Then a more general question about this approach:
Since almost every time something is happening, wouldn't it be too much events going around the subsystems? For example: when the player has lost some health points there would be en event EntityLostHealthEvent going to every SubSystem. There would be quite a lot of such events.


Probably not. The beauty of an event-based system is that all the systems can be very loosely coupled (if not independent). The LifeSubSystem does not know of any other system; all it knows is that when a components Life = 0 it should send an event saying that "EntityID# has 0 Life." Then, anything that is registered to receive those type of events will receive the event and can handle the event appropriately.

In large games there are typically EntityMoved events which fire every time any entity moves. That's a lot of events, but it makes sense. The SoundFXSubSystem would receive this event and play the appropriate sound file (e.g. a Tank moves and the SoundFXSubSystem receives the event and plays the 'TankTracks.wav' file). So, as you can see, there will probably be a ton of events in your game. If you manage memory correctly, you shouldn't have any problem with the number of events being transferred through your game.
Advertisement
Quote:
Just still a small question: what are exactly zones? (For example a zone in my level that when the player enters it, a message pops up: "You entered the enemy's base! Try to find the hidden star as fast as possible!") Is a zone an entity with a zone component? Does the zone component then check all other entities that have a position component whether they are in the zone and if yes send an EntityEnteredZoneEvent?


This would be a Trigger. I'm not sure how Triggers and components work together, but I can tell you that a Trigger has a 3D mesh, usually of a common shape (cube, sphere) that is not rendered to the screen (it could be though) but is taken into account when collisions are calculated and handled. If something collides with the Trigger, the trigger fires an event.
Very helpful post Shakedown, really! ;)

Which one is better, big but few components or small but many components?
Here in this picture from http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/:
components
Is Movement not a part of Physics? Here the components really need each other.
Do I have for each single property of an Entity a component? Like Position, Target, Name, Team, ...
Almost every Entity has a Position, do I still need to have all these components?
Then there are a lot of SubSystems. What exactly is the task of the LifeSubSystem for example? Just listening for events and send them to the corresponding child components, isn't it? For the Render component it's clear what's in the SubSystem: the Render() function (OpenGL drawings for instance). But for a component like Position I don't see the point of a subsystem, since there's only data in the component.
Quote:This would be a Trigger.
Is a Trigger also an Entity?

Yet another question, Shakedown:
Quote:This registering could be done twice; the SubSystem registers with the EventManager, and the components register with the SubSystem.
Why can't I just register the components directly into the EventManager?

A lot of question this time...
I really appreciate our help here!

Aeroz
Quote:Original post by aeroz
Which one is better, big but few components or small but many components?

Depends on your design. Just pick one and try it out? :)

Quote:Original post by aeroz
Is Movement not a part of Physics? Here the components really need each other.
Do I have for each single property of an Entity a component? Like Position, Target, Name, Team, ...

The idea here is that you can mix and match. Some things might move about without being influenced by your physics model. There will always be dependencies between components - physics can't work without position and movement, for instance, and render needs position. You could have some kind of "ProfileComponent" for things like name and team however.

Quote:Original post by aeroz
Almost every Entity has a Position, do I still need to have all these components?

I think there's a strong case for moving position into the entity class, but one of the articles you linked (the MMO one) argues otherwise. You could start out their way and move it later if you need to optimize it, but you can't do that so easily if the entity is just an integer like they suggest (or like in Thief, iirc).

Quote:Original post by aeroz
Is a Trigger also an Entity?

It would be an entity with a collidable/physics, position. The part about it having a script component depends on how and where you are going to fire the events - it could be inside the subsystem also I guess.

Hi!

Since I really like examples and since I'll be always asking myself such things when developing the game, here is another situation one could want in the game:

When 2 Entities are less than 10 units away from each other, something should happen (like a message or anything). Where in the code do I check whether the two Position components are 10 units away from each other? In the PositionSubSystem? I don't want the PositionSubSystem to check the distances from every Position component in the world so I would again have to make some kind of registering the two components into the distance checking part of the PositionSubSystem. This would then check the distance only of these two every frame.

Maybe you have a more elegant way to solve this?

This would be also possible: a trigger entity receives EntityMoved events from the two Entities (actually from the EventManager) and then calculates the distance and does what it wants when d<10. I think this would need a DistanceComponent or something like this.
Presumably you would have some kind of spatial partitioning scheme somewhere in the program. Maybe inside the PositionSubSystem. So instead of having that system store its components in a list, it would store them in something else (octree is an example, though I'm told that for dynamic objects octrees are not so good). In any case, you need to reduce the number of checks to something manageable.
Quote:
Quote:
This registering could be done twice; the SubSystem registers with the EventManager, and the components register with the SubSystem.


Why can't I just register the components directly into the EventManager?


You could, but it would probably be better to have the events go to the SubSystems.

How are you going to create a new LifeComponent? The LifeSubSystem would receive an EntityCreated event and it would create a new LifeComponent attached to this new entity.

If the events have to go through the SubSystem, you can easily control access to the components. You could tell a SubSystem to stop receiving certain events, and thus all child components would stop receiving the events. If the components registered directly with the EventManager, then you would have to iterate through all of the components individually.

Quote:
This would be also possible: a trigger entity receives EntityMoved events from the two Entities (actually from the EventManager) and then calculates the distance and does what it wants when d<10. I think this would need a DistanceComponent or something like this.


Correct. This is a case for Triggers. You would create a Trigger that will fire whenever EntityID# collides with it. You then set the size of the Trigger appropriately. Most likely this Trigger would be a sphere, so you'd set the radius to 10. Then you attach the Trigger to the entity (actually you'd want to attach the Trigger to the Node that your entity is attached to).
Quote:The LifeSubSystem would receive an EntityCreated event and it would create a new LifeComponent attached to this new entity.
Can't I just create the objects like this anywhere in the game?
obj = ObjTemplateMgr::getInstance()->createObject( "HumanTemplate", ObjIdType("Human"));
Maybe the way you said with events to the SubSystems is better than with this Template Manager. But can you briefly say what exactly an event is? Is there an Event base class and then I derive other events from this class like this:
class Event{   EventType m_eventType; /* e.g EventType::EntityCreated */};class EntityCreated : public Event{   Entity* entityCreated;   std::stack<CompIdType> componentsNeeded;};class EntityDied: public Event{   Entity* deadEntity;   Entity* killerEntity;};

Thank you again. I think I now understand the whole thing quite better!
Aeroz
Well, I think I have to try it out myseft. Thank you for all the help!
I just realized the Outboard component-based entity system architecture thread has more than one page... :) Let's read a bit more...
At the end of the year we'll see if my game comes out good. ;)
Aeroz
Good luck =)

This topic is closed to new replies.

Advertisement