0
\$\begingroup\$

I have some hard question for me... I have a nice EventManager, who handle multiple arguments. (no argument, one int, one bool, a GameObject and a bool... but for each sort, I have to create a special dictionnary for this...

public class EventManager : SingletonMono<EventManager>
{
        //here I have many, many class who handle all sorte of different arguments...
         private class UnityEventInt : UnityEvent<int>  {    }


        //here definition of all dictionnnary for each class...
        private Dictionary<GameData.Event, UnityEvent> eventDictionary;
        private Dictionary<GameData.Event, UnityEventInt> eventDictionaryInt;


    private void Awake()
    {
        Init();
    }
    void Init()
    {
        //here initialise all dictionnary
        if (eventDictionary == null)
            eventDictionary = new Dictionary<GameData.Event, UnityEvent>();
        if (eventDictionaryInt == null)
        eventDictionaryInt = new Dictionary<GameData.Event, UnityEventInt>();
        //...
    }

    //One of the startListening
    public static void StartListening(GameData.Event eventName, UnityAction<int> listener)
    {
        if (!Instance)
            return;

        UnityEventInt thisEvent = null;
        if (Instance.eventDictionaryInt.TryGetValue(eventName, out thisEvent))
        {
            thisEvent.AddListener(listener);
        }
        else
        {
            thisEvent = new UnityEventInt();
            thisEvent.AddListener(listener);
            Instance.eventDictionaryInt.Add(eventName, thisEvent);
        }
    }

    //one of the stop
    public static void StopListening(GameData.Event eventName, UnityAction listener)
    {
        if (EventManager.Instance == null)   //au cas ou on a déja supprimé l'eventManager
            return;
        UnityEvent thisEvent = null;
        //si on veut unregister et que la clé existe dans le dico..
        if (Instance.eventDictionary.TryGetValue(eventName, out thisEvent))
        {
            thisEvent.RemoveListener(listener);
        }
    }

    //and one of the trigger
    public static void TriggerEvent(GameData.Event eventName, int param1)
    {
        if (EventManager.Instance == null)   //au cas ou on a déja supprimé l'eventManager
            return;
        UnityEventInt thisEvent = null;
        if (Instance.eventDictionaryInt.TryGetValue(eventName, out thisEvent))
        {
            thisEvent.Invoke(param1);
        }
    }

And... when I want, in some script I do:

EventManager.StopListening(GameData.Event.PlayerAddScore, SomeFuncntion);
EventManager.StartListening(GameData.Event.PlayerAddScore, SomeFuncntion);

EventManager.TriggerEvent(GameData.Event.PlayerAddScore, 1); 

here SomeFunction take 1 argument, but if i wanted to have 2... i have to hard code the case in my EventManager

So... My question is... how can I make that dynamic ? with only one Dictionary ? with only one list ? with good OOP or something ?

And secondly, how can I handle order or the call ? Let's say 2 functions are listening for PlayerAddScore from 2 different script, how can I handle an order between the 2 function ?

Thanks you for help.

\$\endgroup\$
1
\$\begingroup\$

You can't do this easily.

If you absolutely, positively, must have a single function declaration that takes in exactly 1 argument and you want to pass more, and only sometimes, your best bet is to have that 1 argument be an Object[]. You'll have to figure out how many objects and of what type they are in your handler function, but you can do it. It definitely isn't pretty and might cause more problems than it solves.

Your alternative is to make a delegate for each number and type of parameters you wish to use and...have multiple methods that deal with invoking each those delegate calls.

Essentially what this boils down to, is you have an event that has only so many details, and you want to do several different things with it, and that's not something you should be doing. ThingWasClicked() only needs 1 parameter: the thing that was clicked. Passing a second object doesn't really make much sense, especially if you are conditionally sending that second object based on what the listener wants to know about...

No, just send everything all the time and if the listener doesn't care, it just ignores the paramters. There is nothing wrong with

private void HandleSomeClick(GameObject go, int i, bool b, string s, Qaternion q) {
    /*do nothing*/
}
\$\endgroup\$
2
  • \$\begingroup\$ make a delegate for each... done, not pretty... And for the order of the execution of the fonction, how can i handle that ? \$\endgroup\$
    – Ugo Hed
    Mar 17 '18 at 1:24
  • 1
    \$\begingroup\$ As for handling the order, you need some concept of priority. High gets run first, then normal, then low. Keeping in mind that two callbacks with the same priority (before adding priority, its like everything has the same "normal" priority) will be run in the order that they are added. You'll just have to deal with it. \$\endgroup\$ Mar 17 '18 at 7:26

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.