Need Help! UnityEvent: Showing Method Variables in Unity Event Inspector

Hello all!

I have been digging up to find some information but I couldn’t find the answer that I was looking for, or I just didn’t get the solution :slight_smile:

In the inspector for the UnityEvent, once I press the “+” button and assign a specific method there with arguments (or variables) assigned inside the method to appear inside the unity event in inspector view. The reason I would like to do that is to have better control over things from a single area. I might be not following the right path. Please guide me if there is a better way to do it. However, how I imagined is:

Here is the script:

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

namespace TheBossaWorks.Audio
{
    public class AudioFader : MonoBehaviour
    {
        public UnityEvent<AudioSource, float, float, float> audioFadeEvent;



        #region FADE IN/OUT METHODS
        public void FadeInAudio(AudioSource audioSource, float minVolume, float maxVolume, float length)
        {
            minVolume = Mathf.Clamp01(minVolume);
            maxVolume = Mathf.Clamp01(maxVolume);
            StartCoroutine(AudioFadeCoroutine(audioSource, minVolume, maxVolume, length));
        }

        /// <summary>
        /// Public method for fading out the audio slowly lerping.
        /// </summary>
        public void FadeOutAudio(AudioSource audioSource, float minVolume, float maxVolume, float length)
        {
            minVolume = Mathf.Clamp01(minVolume);
            maxVolume = Mathf.Clamp01(maxVolume);
            StartCoroutine(AudioFadeCoroutine(audioSource, maxVolume, minVolume, length));
        }

        #endregion

        #region FADER COROUTINE
        private IEnumerator AudioFadeCoroutine(AudioSource audioSource, float minVolume, float maxVolume, float length)
        {
            float elapsedTime = 0f;

            while (elapsedTime < length)
            {
                elapsedTime += Time.deltaTime;
                audioSource.volume = Mathf.Lerp(minVolume, maxVolume, elapsedTime / length);
                yield return null;
            }
        }

        #endregion

    }
}

If I recall correctly, you can pass at most one parameter to the UnityEvent. In cases like this I would tend to use a struct as the parameter but I don’t think you can specify that in the Inspector.

I suppose this script is just an artificial example? It doesn’t make sense to have a UnityEvent in a script that calls a method in the very same script. If that is the use case simply make those parameters public or SerializeField so you can edit them in the Inspector, and provide a parameterless C# method that other scripts can call.

1 Like

Personally I find the Unity way of connecting up specific business logic from scene to scripts to be a horrible workflow. If something goes wrong, it is extremely difficult to debug. If you dragged 7 different things onto a single button and one doesn’t work two weeks later, how on earth are you supposed to find that?! It’s madness.

Instead, I put a generic “button responder” script on each button and make it send off some kind of message, usually just a string, such as the unique name of the button. Then the code can contain a dispatch method so that when there is a problem, you actually have code where you can place a breakpoint and debug it, plus you can attach as many arguments as you want to things.

In fact, I wrote a package I call “Datasacks” to do exactly this, and more, such as data storage or inter-script signalling.

The diagrammatic setup is:

Datasacks is presently hosted at these locations:

If you are using any version of Unity later than Unity2021, it may be necessary to add this line to your Packages/manifest.json, or add it via the Package Mangler:

"com.unity.ugui": "1.0.0",

You probably want to look at UltEvents as it potentially supports this. The code for UnityEvents is ancient and the few data types it supports for use in the inspector are all hard coded. It has no dynamic support.

1 Like

Thanks for the reply! Yes, you are correct, only a single parameter is visible. Also yes it’s just as an example. I was wondering if this is even possible to achieve. If not ofc, I have to follow some other logic to achieve this.

Maybe I’m not getting this right but I don’t get how to adapt this one to the event I’m imagining.

Oh! This might do it. I’ll take a look at this, thank you!

So I’m assuming there is no built-in way to achieve this?

The entire point is not to entangle a button with all kinds of business logic and connections to your game.

The button should just scream into the void “I AM XYZBUTTON AND I HAVE BEEN PRESSED!”

Somewhere else in your code should be listening and say “Ah, that means do a bunch of things, let’s do them.”

Datasacks is built entirely around that model.

When you mention “a button,” I’m assuming you’re not strictly referring to a UI button. If you are, then this solution doesn’t apply to my case.

That said, I downloaded your package to explore it further. While it might be crystal clear for an experienced developer, it was hella complex for me. You might consider creating a tutorial video with practical use cases to make it more accessible to a wider audience.

Regardless, I appreciate your explanation and I get your point. From what I gathered, it looks like creating an event with multiple inspector-editable variables isn’t possible using built-in tools. I’ll explore alternative methods or see if UltEvents can handle it.

Thx for the response!

Lol, you’re not wrong there. I did include a micro-clicky game of some kind, but it really needs also a “here is what is actually going on” tutorial because you’re right, it is a bit “magic.”

If you’re using UnityEvents randomly in various bits and bobs of your own scripts, well, I guess that’s just a thing that Unity advocates doing, but something I resist. The UnityEditor is an incredibly powerful WSYIWIG tool, but it feels wrong to break up critical flow logic between actual code and the scene.

That’s why the diagram above breaks the code left / right and has only one or a few arrows going into each functional part of the scenes / prefabs. And the one center page (above) called DSM.UserIntent is a single special channel that is used by default for all input, making the final result actually just code on left with a single wire going to each piece of scene UI / stuff. And it is absolutely not limited to UI stuff, as Datasacks can be used for any kind of interop.

To my way of thinking, any GameObject that needs to interoperate with the rest of your scene should have as narrow a band of connections as possible, then handle everything else in code, typically by adding listeners, etc.

The Datasacks package can essentially multiplex data at any level: take many different inputs, produce one output. Take a single input, send it to all listeners, etc.

This lets you ignore the incredibly-strict limitations on UnityEvents, such as those that CodeSmile points out:

That just feels… incomplete to me. Hook up a single “HEY THIS HAPPENED” in the scene and then get back to code where you can reason about execution flow all in one place, rather than stopping to dig around your scene hierarchy.