I would like to get some feedback or alternative solution to following problem.
There are various events in game, for example: DamageEvent
, LocationEnterEvent
, ItemSpawnEvent
.
I would like to create some “actions” to react to those events, for instance:
- Give status effect to damaged unit
- Modify amount of spawned items
- Increase stats of player when enemy dies
I want to make those things to be pluggable inside inspector, not constructed entirely via code.
The problem is that event data must be transformed to fit those actions - simple example:
There is action that gives status effect to target character, this could be method to call:
public void ApplyStatusEffect(Character target);
In my case DamageEvent
provides info about attacker and damage target, so one of those can be used to feed that method above, however ItemSpawnEvent
does not provide that data, or I might need to feed it with custom reference.
My current implementation:
There are EventListener components (for instance DamageEventListener
), they subscribe to given event to call various instructions.
public class DamageEventListener
{
[SerializeReference]
public IDamageEventReceiver[] instructions;
// [...]
public void OnDamage(DamageEvent damageEvent)
{
for (...)
{
instructions[i].HandleDamageEvent(damageEvent);
}
}
}
Instructions (processors) are serializable classes using interfaces to make them available to call and serialize.
public interface IDamageEventReceiver
{
public void HandleDamageEvent(DamageEvent damageEvent);
}
[System.Serializable]
public class DamageEventToCharacter : IDamageEventReceiver
{
public Action action; // This must implement certain interface taking Character as param
public void HandleDamageEvent(DamageEvent damageEvent)
{
action.NameOfMethod(damageEvent.target); // This method would depend on interface
}
}
Advantage of this system is that when something implements given interfaces I can plug anything I want, no GC, simple, modular, fast. The downside is that first I need to check/cast action to given interface (warning in inspector is needed too) and things get complicated if there are made variants of the same function. I would need to code DamageEventToCharacter, DeathEventToCharacter, DamageEventToFloat, DamageEventToSomeFlags, DeathEventToFloat, SpawnEventToFloat, SpawnEventToCharacter and all other variants for various interfaces/events.
Second downside is that Action might need to listen two events with the same parameters, for example changing stats and status effect action both have got the same signature with target Character as parameter. In this case it would be fair solution if I would need to code that thing with separate script, but if I wanted to make that work with interfaces (system above), then I would need different interfaces for each action (at this point I could just reference concrete classes…) and this make everything even worse (more variants).
I would be grateful for any tips.