0

I have a scriptable object class Attack and created some assets from it.

In the Attack asset inspector, I want to be able to reference static functions from other classes, so when something happens, I can grab this static function referenced in Attack and execute it.

Is that possible?


I tried an asset called UltEvents (which claims to get this task done) but it didn't seem work in the newest Unity LTS.

Daniel
  • 7,357
  • 7
  • 32
  • 84

1 Answers1

1

UnityEvent should work, here's an example.

Add a UnityEvent property as usual. The static RunTest method is the callback, the TestCallback is used to invoke the event.

[CreateAssetMenu(menuName = "Attack")]
public class Attack : ScriptableObject
{
    public UnityEvent callback;

    public static void RunTest()
    {
        Debug.Log("Run Test");
    }

    public void TestCallback()
    {
        callback?.Invoke();
        Debug.Log("TestCallback");
    }
}

To select the callback in the inspector, there are 2 situations:

  1. You have an asset/instance associated with the callback, in this example because I define it in the Attack class, the instantiated scriptable object is the asset, you can directly select the callback from the inspector.

    inspector mode

  2. You don't have an asset/instance, you need to switch the inspector to the debug mode and manually populate the callback, see the 2nd screenshot. Pay attention to these fields: Target Assembly, Method Name, Mode, Call State. If the callback needs an argument, you should also fill in one of the Arguments field.

    debug mode

Now if everything is OK, you can see "Run Test" in the console when you call TestCallback.


Alternative 1

The 2nd solution seems like a trick, you can imitate it in a customized way:

[Serializable]
public class MyStaticCallback
{
    public string TypeName, MethodName;
    private Action _callback;

    public void Invoke()
    {
        _callback ??= (Action)Delegate.CreateDelegate(typeof(Action),
            Type.GetType(TypeName), MethodName);
        _callback?.Invoke();
    }
}

public class Attack : ScriptableObject
{
    public MyStaticCallback callback;
}

Alternative 2

Since the callback is static, you can solve this problem in a static way by defining derived classes for each kind of callbacks.

public class Attack1 : Attack
{
    public override void RunCallback() => AnyType.AnyStaticMethod();
}
shingo
  • 18,436
  • 5
  • 23
  • 42
  • I ended up using the option 2 (the one with debug inspector). This is kind of crazy and should be something that was built-in (something like dragging a script file into the inspector and choosing a static function). Your option is the best I can go now. – Daniel Jun 22 '23 at 15:16
  • I'm wondering if this solution uses reflection (since it needs the strings of the class and function name)... if it does, is there a way I can cache the function somehow to avoid reflections after the first execution? – Daniel Jun 22 '23 at 15:17
  • UnityEvent uses reflections too, alternative 1 is its simplified version which caches the delegate. – shingo Jun 23 '23 at 09:01