Best practice for declaring C# events

In the past, I always declared all events in an EventManager, which had a single purpose of collecting all events in a single place. That means that any invoking or subscribing code always knew where the event was defined and could call it using the EventManager high-level qualifier. This was instead of declaring the event in the invoking module.

Generally this worked because sometimes an event could be invoked from more than one script.

However, I’d welcome views on whether this is best practice. So, options include separate EventManager class, EventManager namespace or defining them where they are invoked. What do you generally do and can you see any problems regarding architecture, including issues with multi-player and application scaling? Thanks!

I would try to avoid event brokers, as it creates to much dependencies in my opinion. You always have to have a reference to your broker, which isn’t a problem per say but I just like my scripts to be independant as much as possible. Aside from that, I don’t see any kind of drawback.

What I usually do is declare abstracts ScriptableObject that wrap a C# event, like this

public abstract EventWrapper : ScriptableObject
    public event Action Event;
    public void Raise() => Event?.Invoke();

public abstract EventWrapper<T> : ScriptableObject
    public event Action Event;
    public void Raise(T value) => Event?.Invoke(value);

And then whenever I need an event that would be useful on a wide scale in a project, I just create a class that derives from these classes

[CreateAssetMenu(MenuName = "Events/Player/On Player Damaged", FileName = "OnPlayerDamaged"]
public OnPlayerDamaged : EventWrapper<float>
{    }

[CreateAssetMenu(MenuName = "Events/Player/On Player Killed ", FileName = "OnPlayerKilled "]
public OnPlayerKilled : EventWrapper
{     }

What I like about that is that you can extend what happens when this or that happens with components that aren’t relying on dependencies on other components.

What I dislike about that is the amount of assets of the likes you can have to create. Whenever there’s something that has to be broadcasted, you create an asset, and you end up with a shitload of them. And you also need to be carefull to clean your events, since there are encapsulated in a scriptable object, in editor, you can get errors if you don’t reset events.

I still use C# events outside of scriptable objects when I need an event that would be used on a local scale, conceptually. When animating UI through code, for instance, I declare an event that fires when the animation has been done.