Dynamic vs Static UnityEvents?

Hi fellow game developers,

Today I discovered UnityEvents, which seemed like they’d let me basically have delegates that I can set in the inspector. I thought that if I created a method:

void ProcessAttack(string attackAnimation, float damage, float delay)

and a class AttackEvent which extends UnityEvent<string,float,float>

I would be able to set the values in the editor. Instead the function gets listed as a dynamic function. How do I make my UnityEvent static so I can set the parameters in the Editor?

  • Thanks in advance
1 Like

Remember to mark your custom event class as Serializable.

using UnityEngine;
using UnityEngine.Events;

namespace EventTest {
    [System.Serializable] // <-- important, often forgotten!
    public class IntFloatFloatEvent : UnityEvent<int, float, float> { }

    public class SomeTestBehaviour : MonoBehaviour
    {
        [SerializeField] private IntFloatFloatEvent someEvent;

       void Start()
       {
           someEvent.Invoke(1, 1.5f, 2.5f);
       }

       public void PrintSomeEvent(int someInt, float someFloat, float someOtherFloat)
       {
           Debug.LogFormat("Event received: {0}, {1}, {2}", someInt, someFloat, someOtherFloat);
       }
   }
}
1 Like

Coming back to this, I think I misread the original question. The OP was seeking a way to have a custom unity event show up in the Static section inside of the event listener, so that he could have his artists and designers assign the values to be invoked via the editor. I’m leaving my original answer because it is useful to be reminded to mark the event as serializable. I often forget that!

In truth, I don’t know of a way to teach unity to serialize multiple values in an event. Unity only has editors for single, basic values (int, float, string, bool, Object). It doesn’t have an editor for a multiple valued event, nor does it seem to support a custom struct. There are some older threads that seem to confirm this lack of support for multiple event parameters being serialized in the inspector (Unity Events, passing multiple arguments - Unity Engine - Unity Discussions and UI Doesn't Accept Functions with more than two Arguments or Arrays? - Unity Engine - Unity Discussions)

1 Like

This might be something @Flipbookee 's Script Inspector 3 can address — he’s already buffed the default UnityEvent editor in several ways (for example, adding a widget you can click to jump directly to the method hooked up to any event).

I’m not sure whether it supports multiple arguments, or if that’s even possible, but if anybody can do it, he can!

I tend to wrap the whole thing in a data class or struct of its own. It’s crude, but it works.

Unity’s UnityEventBaseInspector class (which btw I feel should be broken up into multiple smaller classes) only has code to draw upto one field for static events. this is because UnityEventBase (or more specifically the internal PersistentCall class) is limited in the cached data that it serializes:

//UnityEventBase has this field that it serializes
       PersistentCallGroup m_PersistentCalls;// holds a list of all the methods to call when the event is invoked

//and PersistentCallgroup has this
       List<PersistentCall> m_Calls;

//each PersistentCall has these fields
       UnityEventCallState m_CallState // an enum for off, editor and runtime, or runtime only
       PersistentListenerMode m_Mode // enum determining which internal delegate to call and which inputs to draw in inspector
       UnityEngine.Object m_Target // the instance which to call the method on
       string m_TypeName // the concrete type name of the target (needed for polymorphism)
       string m_MethodName // the name of the method to call in target
     
       ArgumentCache m_Arguments //container class which holds the arguments that are passed into the calling function, used for static calls

//ArgumentCache has the following variables
       UnityEngine.Object m_ObjectArgument
       string m_ObjectArgumentAssemblyTypeName // used to confirm if objectArgument is valid
       int m_IntArgument
       float m_FloatArgument
       string m_StringArgument
       bool m_BoolArgument

as you can see with the ArgumentCache class it really only has enough storage for one of each datatype and when you really get down into the editor scripting, there no clean way of showing multiple fields with the limited fields availible (can’t show any function(int,int) calls for example since theres only one intArgument field per call) in the ArgumentCache class. conceivably UnityEventBase could have held something like a List of ArgumentCache to support multiple fields in the inspector. but it would also complicate the implementation inside the PersistentCall, so it currently doesn’t. if you wanted to add multiple fields in the inspector for event it then an event package would have to practically mirror nearly every class in the UnityEngine.Events namespace (since most of the classes are internal) just so they can add that one feature

On a side note:
this should also help explain why some data will persist as you change which methods an event calls while other times inexplicibly lose the data. for example you switch from one method with a GameObject argument to another method with a gameObject argument, the referenced gameobject is kept, since they are both using the same ArgumentCache. Or switch from a float argument to a bool arguement, then back to a float the original float is still saved.

…however if target is deleted (or prefab’d incorrectly), you rename/delte the class thats targeted, rename/delete the method being called, or put the class in a different namespace the inspector will lose the reference (because the reflection calls now return null since they still have the old string values)

3 Likes

Requires a paid asset (OdinInspector), but there’s this: GitHub - 7ark/BetterEvents-Deprecated: A replacement for UnityEvents that are: better.