Hi!

I am trying to move from using the Mecanim controller over to SkeletonAnimation in unity, but one hurdle i have yet to overcome is that I extensively use events in my animations to trigger all kinds of things. Its not really an option to add the events in spline as that workflow would be to cumbersome.

Can anyone point me in the right direction of how i would go about this? I did search extensively beforehand and could not find any good resources on this, except for the sentence: "Since the Spine runtimes are source-available and fully modifiable in your project, you can of-course define and raise your own events in AnimationState or in whatever version of it you make. See the official spine-unity forums for more information." .. on https://esotericsoftware.com/spine-unity-events - so .. here I am ๐Ÿ™‚

    Related Discussions
    ...

    starfckr There are multiple ways to achieve this:

    • a) You could write a conversion script which automatically adds the Mecanim events back into your Spine project, then re-export the skeleton assets. For that you could first ensure your skeletons are exported as .json, then go through the events of the Mecanim animation clips and add the respective events to the .json file (on a text-modification level), then you can use the Spine CLI to import the modified .json data to a Spine project (like Spine - Import Data.. in the Spine Editor GUI).

    • b) You could add events from Mecanim animation clips after the skeleton was imported. You could write your own SkeletonDataModifierAsset for that, which would add the events from the Mecanim clips to the imported SkeletonData.

    The first option requires more scripting work, but comes with the advantage of having everything cleanly contained in the Spine project. The second option requires less coding, but comes with the disadvantage of not having everything in one place.

    In case I forgot about an easier alternative, please do share your thoughts here. ๐Ÿ™‚

      Harald

      Thanks for the detailed answer, but i might have phrased the question a bit wrong. I dont really need to do a conversion of existing events (its so few that i can handle that manually), what i want to achieve is to add new events based on time or frames to an animation through scripting within unity.

      The reason why i cannot add this in spline itself is that the animations are outsourced, and its just not worth the back and forth when doing quick iterations.

      So: How can I add new events to an animation through scripting, and ideally also events that have custom objects (enums, scriptable_objects, etc) attached to them.

      My idea here initially was to just have a simple class holding the animationAssetReference, and that class is referenced when the statemachine loads up animations, and within that class i would also be able to set the various events through the inspector. Pretty simple in theory - i just need to figure out how to get started on actually adding events to an animation.

        starfckr Thanks for the detailed answer, but i might have phrased the question a bit wrong. I dont really need to do a conversion of existing events (its so few that i can handle that manually), what i want to achieve is to add new events based on time or frames to an animation through scripting within unity.

        Oh, ok. Thanks for the clarification.

        starfckr So: How can I add new events to an animation through scripting, and ideally also events that have custom objects (enums, scriptable_objects, etc) attached to them.

        To author your events in Unity you have the whole Unity scripting API at your disposal then.
        Then you would still want to append the added events to the respective Spine Animation object at the respective SkeletonData. You can still use SkeletonDataModifierAsset for that, as described in (b) in the above posting.

        In order to get custom object or asset references linked to your events, you could write a script that uses e.g. the string or int parameter at the given event (see the API reference here). The script then maps your assets to a string/int when authoring and back to an asset reference when reading it back. Alternatively you could modify the spine-csharp source code accordingly and add an object reference to the Event or EventData class.

          Harald
          Understood! So.. something like this could work? .. or am i barking up the wrong tree here?

          public class ClipEvent
              {
                  public string name;
                  public int key;
                  [Range(0, 1)]
                  public float fireAt;
              }

          This would then be on a animationManager where i reference all the AnimationReferenceAssets and pair them up with their corresponding state so i can fire of animations from my statemachine.
          I would then, when setting that up - also add all relevant events.

          public void SetEvents(AnimationReferenceAsset asset)
                  {
                      Spine.EventTimeline newTimeline = new EventTimeline(asset.Animation.Timelines.Items[0].FrameCount);
                      foreach (ClipEvent evnt in events)
                      {
                          Spine.EventData eventData = new EventData(evnt.name);
                          eventData.Int = evnt.key;
                          Spine.Event newEvent = new Spine.Event(Mathf.Lerp(0, asset.Animation.Duration, evnt.fireAt), eventData);
                          newTimeline.SetFrame(Mathf.RoundToInt(newEvent.Time / 30), newEvent);
                      }
                      
                      asset.Animation.Timelines.Add(newTimeline);
                  }

          Havent tested this yet, but a few questions that pops up is how to handle the framecount for the timeline, as the events are added with a reference to time in floats.

          @starfckr The code is looking good in general, however this constructor call is allocating for too many keyframes (event keys):

          Spine.EventTimeline newTimeline = new EventTimeline(asset.Animation.Timelines.Items[0].FrameCount);

          You should be good with new EventTimeline(events.Count); from the number of ClipEvents in your events collection.

          In general we recommend looking at the respective source code section, like SkeletonJson.cs : L1088 in this case. Then you can also use a debugger to step through the code and observe the already working skeleton loading scenario.

            Harald
            Thanks for pointing me in the right direction, I really appreciate it! I will reach out if i have any further questions as i delve deeper into this ๐Ÿ™‚