3
\$\begingroup\$

I apologize if this has been answered already. I've looked around here, and read a few blog posts, but none seem to fully answer my question.

I am writing an Entity Component System.

  • Entity is a store for Components, and is the central GameObject.
  • Component is just a POD struct that describes some attribute (Health, Mana, etc.)
  • System dictates the laws of the game world. Systems describe how an Entity will behave based on the Components that entity has, and the data stored within the Component. Additionally, a System can interact with other Systems using Events.

A pretty straight-forward and common approach. Now, the issue I am having is when an Event should interact with an Entity. For example, a DieOnCollision event for some Entities, or a HealOnUse event for others.

At first, I thought about just making a bunch of Systems for every type of event. An Entity would subscribe to these Systems, just like other Systems, except their Update function would do nothing. Instead, they only operated once per frame when passed an Event from the EventQueue.

I don't like this approach, because it is putting the System in charge of specific Entities, rather than operating on a collection of Entities.

Another approach I thought of was just creating a Component for each event, each of which holds a function pointer. When an event happens, such as ExplosionEvent, a list of entities in the area is given to the EventHandler, which then checks for the OnExplosionEvent component and calls the corresponding function (or maybe queues it up so all the functions can be processed in order).

I'm not too fond of this approach either, because it puts behavior into a component and it puts the EventHandler in charge of telling the Entities. Of course, I could probably just have the EventHandler pass the Event to GameWorld which then passes it to the Entities who have the needed components, but it still puts behavior into a component, which I want to avoid.

One last idea that just came to me would be to give the Entity a map of events it can listen for, something like std::map<EventID, FunctionPointer>. The entities could then be notified of Events during event handling, and their functions could be queued up. I do like this approach, but I am curious if there are any other suggested ways to handle Events pertaining to an Entity rather than a System.

\$\endgroup\$
3
\$\begingroup\$

The DieOnCollision event couples behavior to an event. This causes tight coupling and could be why you're having trouble deciding how to handle these use cases. Instead I would concentrate on the fact you want to perform some behavior when a collision occurs, therefore it makes logical sense to expose some way to know when a collision has happened.

Since collision data is often useful to numerous logic systems, your CollisionSystem detects collisions, resolves them, and stores the resolved data in some queriable list.

Then there is any number of logic systems that store a list of entities that contain a specific marker component and use the CollisionSystem's resolved data to determine whether entities with the special marker component has a collision and perform specific behavior.

\$\endgroup\$
  • \$\begingroup\$ I think I get what you're saying - when a collision is detected between my two BoundingBoxes, store the generic collision event in a query-able list that can be accessed by the other logic systems. So, when the BallCollisionSystem asks for a collision event that happened between a ball and another object, it can bounce the ball and send a DamageEvent for the other object. If the object happens to be subscribed to a system that eats DamageEvents, then it'll take damage - otherwise nothing will happen. But that "if" could also cause a lot of branching... I'm probably pre-optimizing, tho. \$\endgroup\$ – Acorn Jan 3 '16 at 4:37
  • 1
    \$\begingroup\$ @Acorn Don't worry whether the other object is subscribed to eat DamageEvents, just send them. If the entity is in the list of damagable entities list for the DamageSystem, it will act accordingly. If it isn't, nothing happens. Sending events do not necessarily imply they'll be reacted upon. And a source system of events should not care who or what intercepts them and processes them. \$\endgroup\$ – Naros Jan 4 '16 at 15:03
  • \$\begingroup\$ I'm a little late getting to this, but to sum up: Don't have a system ask for a specific event(such as one involving ID 4), just pass it the list of all of the CollisionEvents. The system will iterate over the list, and if it happens to see a CollisionEvent involving ID 4 or whatever ID's are subscribed to it, then it'll do whatever; it not then it does nothing? \$\endgroup\$ – Acorn Jan 10 '16 at 22:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.