Skip to content

Instantly share code, notes, and snippets.

@pharan
Last active May 17, 2024 02:22
Show Gist options
  • Save pharan/5fd12db1aac7977879a0fc0c01876c51 to your computer and use it in GitHub Desktop.
Save pharan/5fd12db1aac7977879a0fc0c01876c51 to your computer and use it in GitHub Desktop.
spine-csharp EventTimelineExtensions

EventTimelineExtensions.cs

EventTimelineExtensions.cs contains a static class with a set of convenience methods/extensions that help the user create or modify Spine.EventTimelines at runtime.

Sample usage in Unity: EventTimelineSample.cs

using UnityEngine;
using System.Collections.Generic;

using Spine;
using Spine.Unity;

public class EventTimelineSample : MonoBehaviour {

	void Start () {
		var skeletonAnimation = this.GetComponent<Spine.Unity.SkeletonAnimation>();
		Spine.SkeletonData skeletonData = skeletonAnimation.skeleton.data;

		// Create EventData objects.
		Spine.EventData myEventABC = new Spine.EventData("ABC");
		Spine.EventData myEventDEF = new Spine.EventData("DEF");
		// Add EventData to SkeletonData. Not necessary but good if you want to keep your SkeletonData together or share with other instances.
		// skeletonData.events.Add(myEventABC);
		// skeletonData.events.Add(myEventDEF);

		// EventData can also be pre-existing from what you added in Spine editor.
		//Spine.EventData myExistingEventData = skeletonData.FindEvent("my event I added in Spine");

		// Make a temporary list to be converted into an EventTimeline later.
		List<Spine.Event> myEventList = new List<Spine.Event>();
		myEventList.Add(new Spine.Event(0.5f, myEventABC)); // fire myEventABC at 0.5 seconds.
		myEventList.Add(new Spine.Event(1.0f, myEventDEF)); // fire myEventDEF at 1 second.
		myEventList.Add(new Spine.Event(2.0f, myEventDEF)); // fire myEventDEF again at 2 seconds.
		//myEventList.Add(new Spine.Event(3.0f, myExistingEventData)); // fire myExistingEventData at 3 seconds.

		// Convert the temporary list into an EventTimeline and add it to your Spine.Animation.
		Spine.EventTimeline myNewEventTimeline = myEventList.ToEventTimeline(); // This is an extension method.

		// Find the animation you want to add the event timeline to and add the new timeline to it.
		Spine.Animation myAnimation = skeletonData.FindAnimation("my run animation");
		myAnimation.Timelines.Add(myNewEventTimeline);

		// Test the animation with the added events.
		skeletonAnimation.state.SetAnimation(0, myAnimation, true);
		skeletonAnimation.state.Event += (state, trackIndex, e) => Debug.Log(e.Data.name + " fired at " + Time.time);
	}

}
/******************************************************************************
* Spine Runtimes Software License
* Version 2.3
*
* Copyright (c) 2013-2015, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to use, install, execute and perform the Spine
* Runtimes Software (the "Software") and derivative works solely for personal
* or internal use. Without the written permission of Esoteric Software (see
* Section 2 of the Spine Software License Agreement), you may not (a) modify,
* translate, adapt or otherwise create derivative works, improvements of the
* Software or develop new applications using the Software or (b) remove,
* delete, alter or obscure any trademarks or any copyright, trademark, patent
* or other intellectual property or proprietary rights notices on or in the
* Software, including any copy thereof. Redistributions in binary or source
* form must include this license and terms.
*
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
using System.Collections.Generic;
namespace Spine {
public static class EventTimelineExtensions {
/// <summary>Finds an event timeline in an animation. May return null.</summary>
static public EventTimeline FindEventTimeline (this Animation animation, EventData eventData) {
return FindEventTimeline(animation, (x) => x == eventData);
}
/// <summary>Finds an event timeline in an animation. May return null.</summary>
static public EventTimeline FindEventTimeline (this Animation animation, string eventDataName) {
return FindEventTimeline(animation, (x) => x.name == eventDataName);
}
static EventTimeline FindEventTimeline (this Animation animation, System.Predicate<EventData> EventMatchFunction) {
var timelines = animation.timelines;
var timelinesItems = timelines.Items;
for (int i = 0, n = timelines.Count; i < n; i++) {
var eventTimeline = timelinesItems[i] as EventTimeline;
if (eventTimeline == null) // Was not an eventTimeline.
continue;
var events = eventTimeline.Events;
if (events.Length < 1) // Was an empty eventTimeline for some reason.
continue;
if (EventMatchFunction(events[i].Data))
return eventTimeline;
}
return null;
}
static public List<Event> ToEventList (this EventTimeline eventTimeline) {
return new List<Event>(eventTimeline.Events);
}
static public EventTimeline ToEventTimeline (this List<Event> eventList, EventTimeline eventTimeline = null) {
if (eventList == null || eventList.Count < 1)
throw new System.ArgumentException("eventList cannot be null or empty.");
// 1. Ensure capacity.
int newKeyCount = eventList.Count;
if (eventTimeline == null) {
eventTimeline = new EventTimeline(newKeyCount);
} else {
// Overwrite existing EventTimeline values.
int oldKeyCount = eventTimeline.FrameCount;
if (oldKeyCount != newKeyCount) {
// orphan old arrays
eventTimeline.Events = new Event[newKeyCount];
eventTimeline.Frames = new float[newKeyCount];
}
}
// 2. Sort original list according to key time first
eventList.Sort(
(x, y) => x.Time.CompareTo(y.Time)
);
// 3. Set new values.
for (int i = 0; i < newKeyCount; i++)
eventTimeline.SetFrame(i, eventList[i]);
return eventTimeline;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment