Multiple functions in one unity event

So I am trying to make a menu manager that opens and closes menus and I want to be able to have an on open and an on close function. The way that I get all the functions right now for all the menus is public UnityEvent[] menuCallFunctions; and then to use them menuCallFunctions[n].Invoke(); I have also seen that there is a plus button that lets me add more functions:
.
My question is: how would I count the number of functions that are there and then how would I, for example, call the second function given.

I don’t think the UnityEvent API exposes that. But the real questions is why would you want to? The point of events is that the entity that kicks off the event doesn’t know or care who is listening to it.

Edit: I guess technically you could get the target with this: Unity - Scripting API: Events.UnityEventBase.GetPersistentTarget and invoke a method on it with the method name:
Unity - Scripting API: Events.UnityEventBase.GetPersistentMethodName
But it seems like a bad idea.

Could you elaborate why you’d want to have an array of events? Typically you’d have one instance for a specific event, not multiple ones for the same one. For each event, you can then add multiple subscribers (that’s what the plus exists for).
Instead of keeping all events in an array, you should have one self-descriptive event field per “event” that may occur, because noone wants to guess which event in the array one needs to subscribe to.

Like @PraetorBlue has already mentioned, the one who raises the event usually doesn’t care who is going to be notified, and how many subscribers it has (though a C# event needs to check whether or not there is any before the event is raised).

1 Like

So the reason that I am using an array is that I have made a menu controller and it controls many menus so what I give in the controller is a key (for example ESC) and then a function to call to toggle the menu on or off, so an array of all of the events for each menu. What I want to do is to be able to add an option to give 2 of those event things so that it can call an on open and an on close function. Idk if I am confused about how the events work as I am sorta new to all this event stuff.

For reference here is the menu controller:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class MenuControler : MonoBehaviour
{
    public UnityEvent[] menuCallFunctions;
    public KeyCode[] keys;
    bool anyMenuOpen = false;
    bool[] isMenuOpen;

   
    void Start()
    {
        //Populate the isMenuOpen array
        isMenuOpen = new bool[Mathf.Min(keys.Length, menuCallFunctions.Length)];
    }
    //Every frame look if any of the keys have been taken.

    public void OpenMenu(int menuIndex)
    {
        //Close all other menus before opening this one
                int length2 = isMenuOpen.Length;
                for (int n = 0; n < length2; n++)
                {
                    //Make sure that you are not toggling the current menu.
                    if(n!=menuIndex){
                        //Invoke the funtion of open menus to close them (because its a toggle)
                        if (isMenuOpen[n])
                        {
                            menuCallFunctions[n].Invoke();
                            isMenuOpen[n] = false;
                        }
                    }
                }
                //Invoke the open or close the function because its a toggle
                menuCallFunctions[menuIndex].Invoke();
                isMenuOpen[menuIndex] = !isMenuOpen[menuIndex];
               
                //Check if any menus are open at the moment and set the anyMenuOpen variable accordingly
                for (int n = 0; n < length2; n++)
                {
                    if (isMenuOpen[n])
                    {
                        anyMenuOpen = true;
                    }
                }
    }
    void Update()
    {
        int length = Mathf.Min(keys.Length, menuCallFunctions.Length);
        for (int i = 0; i < length; i++)
        {
            if(Input.GetKeyUp(keys[i]))
            {
                OpenMenu(i);
            }
        }
        return;
    } 
}

EDIT: I just had this idea but is what I want to do better as a 2d array?

As mentioned above the entire concept behind events is that whatever is triggering the event doesn’t need to have any knowledge of what’s being called as a result of that. It’s like your close button is shouting into the air “Hey! I’ve been clicked!” Other components are listening for that shout (that’s what you put into the UnityEvent in the inspector), but the close button doesn’t ever actually know whether the event got responded to, nor should it. The close button’s responsibility is done after it shouts.

Just make them 2 different events. Open and close are two entirely different functionalities; trying to mash them into one array will gain you nothing.

If I understand your goal correctly, which is that you want a common/repeatable structure to hold commonly-used event types, you could define a class that holds multiple UnityEvents. For example:

public MenuCallFunctions someWindowFunctions;

[System.Serializable]
public class MenuCallFunctions {
public UnityEvent onClose;
public UnityEvent onOpen;
// etc
}

someWindowFunctions.onClose.Invoke();

This seems to be a great explanation and if I wanted to make a bunch of menus what I would do is make an array of the struct. Thanks a lot for your help! I always love a clear and concise answer.

I think I understand what you’re trying to do here. However, try to look at it from a different perspective. You won’t really need events for that.

An event is usually declared by a type in order to raise a notification about something that is about to happen, is happening, or has happened. The idea is to inverse the control flow and achieve less coupling. It generally does not say what should or must happen, because if it did, you wouldn’t really need an event, right?

Take your menus. They can be opened, and closed.
The controller wants to control opening and closing according to some key presses.
So the controller instructs the menus what to do. It knows something about the types it wants to address, so there is no real need for an event, but rather a “type/communication contract”. I.e. it expects to talk to instance that satisfies some criteria, e.g. these things should have an Open and a Close method. So just have an array of Menus, which have an Open and a Close method.

Now on the other hand, your menus are the ones that could have an Opened, and a Closed event. Here you’ve got events that occur at some “arbitrary” point, and to which some other things in your application might want to react to.

When you close a menu, it’ll do its thing in order to shut down and then raises its “Closed” event. Note that this is just a notification that something has happened in terms of “I’m a menu, I’m closed now - if anyone cares, go ahead”. It does not say what should happen next,it’s only a menu trying to raise some attention and let the world know it’s closed now - maybe there’s nothing that happens when a particular menu closes, perhaps the game paused when the menu was opened, and resumes when it closes again. But still the menu itself doesn’t care about that, it’s not its responsibility.

Ok, I think that I am understanding what I need to do, but I am still wondering how to call the function because I don’t want it to be hardcoded and I sorta like the way that events let me chose what function from what object with the magic that unity has to remember what object I am talking about. I think the reason that I am using events is that that is just the first way which I saw of calling functions because I think that UI buttons use events but with a different goal from what I am trying to do.

As I said, you can do that. But if you know that the objects you want to address (via the events array) are all of the same kind you’ll be better off declaring a type for them and call the methods directly.

What you’ve done (more or less) suggests that you really want to map arbitrary actions to your keys, like a quick&dirty key-input mapping system for basically everything you want to handle… otherwise, one would normally expect that you deal with a certain type of objects and that you throw these objects into the array via the inspector.

I do get your point about Unity’s “magic”, but that can also become a nightmare if you suddenly can’t see anymore where those methods are currently being used, because there’s no easy way to track that.