[Unity] Animator Event usability

Tom GrzembkeTom Grzembke
4 min read

What is an Animation Event?

Animation Events are little flags, that allow you to trigger a method on an animation frame.

The “Add Event” button is highlighted in light blue and the actual flags I set, are pink here.

What problem do I want to fix?

Those Animation Events only show you methods from a script on the same GameObject as the Animator.

It seems logical to write some kind of handler for use cases like a Player, which has lots of animation events and based signal transfer.

This is tedious to set up and especially a problem for quick testing and smaller use cases like a plant flowing in the wind or props in general.

My Solution

A somewhat dynamic handler that lets you add UnityEvents as an array like this:

(The following script still has to be on the animated object)

using UnityEngine;
using UnityEngine.Events;

/// <summary> This script should be attached to an animated 
///Object to utilize the Unity Events through this </summary>
public class AnimationEventHandler : MonoBehaviour
{
    [SerializeField] UnityEvent[] onAnimEvents;

    /// <param name="eventID"> The ID of the corresponding onEvent array ID</param>
    void OnAnimEventID(int eventID)
    {
        onAnimEvents[eventID]?.Invoke();
    }

    /// <summary> Be careful with statemachine 
    ///blending and instantiating! Might need a spawn limit per frame bunch</summary>
    void InstantiateObj(Object obj)
    {
        Instantiate(obj, transform.localPosition, Quaternion.identity);
    }
}

Small Animation Event Usage Tutorial

Now you can add the script via the animation window and inspector in Unity like this:

  1. Hover over your desired frame (GameObject needs to be selected) and add an Animation Event through the small flag symbol.

  1. Select the AnimationEventHandler in the Inspector window after you clicked on your created flag.

  1. Select the OnEvent Method and set the “Int” parameter to your desired array element that should get called.

Thanks for Reading!

The script that you received hopefully helps you with prototyping and or prefab workflow and scrapes a bit more usability of the animation Events.

There’s a huge discussion about Unity Events regarding their debugging capability and I had my fair share of losing to and with them. Still, it fits the dynamic solution I’m trying to achieve here best.

Extra Section

There was a request to add note functionality to each animation event for debugging and tracking purposes.

It adds a bit of complexity, though, and may be over-engineered, which is why this section exists.

Here’s my updated version which utilizes the AnimationEvent field, which gives us the option to pass more than one parameter through the Inspector:

The “Float” and “Int” parameters now act as your “eventID” from the prior script.
“Float” gets prioritized when it’s set to anything else than 0.

You can also add a comment in the “String”, but that will only add that comment on runtime and if you don’t set one in the next step. (You can still use the OnAnimEventID Method if you don’t like the string variant)

This is how an event will look like in the inspector from the AnimationEventHandler. As I said the comment here gets prioritized and saved other than it would in the step prior:

And here’s the code for it:

using UnityEngine;
using UnityEngine.Events;

/// <summary> This script should be attached to an animated Object to utilize the Unity Events through this </summary>
public class AnimationEventHandler : MonoBehaviour
{
    [SerializeField] AnimationUnityEvent[] onEvents;

    /// <param name="eventID"> The ID of the corresponding onEvent array ID</param>
    void OnAnimEventID(int eventID)
    {
        onEvents[eventID].animEvent?.Invoke();
    }

    /// <param name="eventID"> The ID of the corresponding onEvent array ID</param>
    void OnAnimEvent(AnimationEvent _animEvent)
    {
        int animeventID = DetermineAnimEventID(_animEvent);

        if (onEvents.Length <= animeventID) return;

        onEvents[animeventID].animEvent?.Invoke();

        if (onEvents[animeventID].eventNote == "")
            onEvents[animeventID].eventNote = _animEvent.stringParameter;
    }

    /// <summary> prefers the float parameter on an animEvent if its set, else takes the int parameter </summary>
    int DetermineAnimEventID(AnimationEvent _animEvent)
    {
        return _animEvent.intParameter != 0 ? _animEvent.intParameter : (int)_animEvent.floatParameter;
    }

    /// <summary> Be careful with statemachine blending and instantiating! Might need a spawn limit per frame bunch</summary>
    void InstantiateObj(Object obj)
    {
        Instantiate(obj, transform.localPosition, Quaternion.identity);
    }
}

[System.Serializable]
public struct AnimationUnityEvent
{
    [Tooltip("To keep track of the animation functionality")]
    public string eventNote;
    public UnityEvent animEvent;
}
0
Subscribe to my newsletter

Read articles from Tom Grzembke directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Tom Grzembke
Tom Grzembke