Event timeline for spine-csharp.

This commit is contained in:
NathanSweet 2013-09-22 22:33:38 +02:00
parent a16bb5b5d6
commit d2d6919afb
9 changed files with 423 additions and 81 deletions

View File

@ -105,6 +105,8 @@
<Compile Include="src\Attachments\RegionAttachment.cs" />
<Compile Include="src\Bone.cs" />
<Compile Include="src\BoneData.cs" />
<Compile Include="src\Event.cs" />
<Compile Include="src\EventData.cs" />
<Compile Include="src\Json.cs" />
<Compile Include="src\Skeleton.cs" />
<Compile Include="src\SkeletonBounds.cs" />

View File

@ -48,27 +48,47 @@ namespace Spine {
Duration = duration;
}
/** Poses the skeleton at the specified time for this animation. */
/** @deprecated */
public void Apply (Skeleton skeleton, float time, bool loop) {
Apply(skeleton, time, time, loop, null);
}
/** Poses the skeleton at the specified time for this animation.
* @param lastTime The last time the animation was applied. Can be equal to time if events shouldn't be fired.
* @param events Any triggered events are added. May be null if lastTime is known to not cause any events to trigger. */
public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, List<Event> events) {
if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null.");
if (loop && Duration != 0) time %= Duration;
if (loop && Duration != 0) {
time %= Duration;
lastTime %= Duration;
}
List<Timeline> timelines = Timelines;
for (int i = 0, n = timelines.Count; i < n; i++)
timelines[i].Apply(skeleton, time, 1);
timelines[i].Apply(skeleton, lastTime, time, 1, events);
}
/** @deprecated */
public void Mix (Skeleton skeleton, float time, bool loop, float alpha) {
Mix(skeleton, time, time, loop, null, alpha);
}
/** Poses the skeleton at the specified time for this animation mixed with the current pose.
* @param lastTime The last time the animation was applied. Can be equal to time if events shouldn't be fired.
* @param events Any triggered events are added. May be null if lastTime is known to not cause any events to trigger.
* @param alpha The amount of this animation that affects the current pose. */
public void Mix (Skeleton skeleton, float time, bool loop, float alpha) {
public void Mix (Skeleton skeleton, float lastTime, float time, bool loop, List<Event> events, float alpha) {
if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null.");
if (loop && Duration != 0) time %= Duration;
if (loop && Duration != 0) {
time %= Duration;
lastTime %= Duration;
}
List<Timeline> timelines = Timelines;
for (int i = 0, n = timelines.Count; i < n; i++)
timelines[i].Apply(skeleton, time, alpha);
timelines[i].Apply(skeleton, lastTime, time, alpha, events);
}
/** @param target After the first and before the last entry. */
@ -96,7 +116,7 @@ namespace Spine {
public interface Timeline {
/** Sets the value(s) for the specified time. */
void Apply (Skeleton skeleton, float time, float alpha);
void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents);
}
/** Base class for frames that use an interpolation bezier curve. */
@ -116,7 +136,7 @@ namespace Spine {
curves = new float[(frameCount - 1) * 6];
}
abstract public void Apply (Skeleton skeleton, float time, float alpha);
abstract public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents);
public void SetLinear (int frameIndex) {
curves[frameIndex * 6] = LINEAR;
@ -202,7 +222,7 @@ namespace Spine {
Frames[frameIndex + 1] = angle;
}
override public void Apply (Skeleton skeleton, float time, float alpha) {
override public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents) {
float[] frames = Frames;
if (time < frames[0]) return; // Time is before first frame.
@ -262,7 +282,7 @@ namespace Spine {
Frames[frameIndex + 2] = y;
}
override public void Apply (Skeleton skeleton, float time, float alpha) {
override public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents) {
float[] frames = Frames;
if (time < frames[0]) return; // Time is before first frame.
@ -292,7 +312,7 @@ namespace Spine {
: base(frameCount) {
}
override public void Apply (Skeleton skeleton, float time, float alpha) {
override public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents) {
float[] frames = Frames;
if (time < frames[0]) return; // Time is before first frame.
@ -341,7 +361,7 @@ namespace Spine {
Frames[frameIndex + 4] = a;
}
override public void Apply (Skeleton skeleton, float time, float alpha) {
override public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents) {
float[] frames = Frames;
if (time < frames[0]) return; // Time is before first frame.
@ -405,7 +425,7 @@ namespace Spine {
AttachmentNames[frameIndex] = attachmentName;
}
public void Apply (Skeleton skeleton, float time, float alpha) {
public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents) {
float[] frames = Frames;
if (time < frames[0]) return; // Time is before first frame.
@ -421,6 +441,57 @@ namespace Spine {
}
}
public class EventTimeline : Timeline {
public float[] Frames { get; private set; } // time, ...
public Event[] Events { get; private set; }
public int FrameCount {
get {
return Frames.Length;
}
}
public EventTimeline (int frameCount) {
Frames = new float[frameCount];
Events = new Event[frameCount];
}
/** Sets the time and value of the specified keyframe. */
public void setFrame (int frameIndex, float time, Event e) {
Frames[frameIndex] = time;
Events[frameIndex] = e;
}
public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents) {
float[] frames = Frames;
if (time < frames[0]) return; // Time is before first frame.
int frameCount = frames.Length;
if (lastTime >= frames[frameCount - 1]) return; // Last time is after last frame.
if (lastTime > time) {
// Fire events after last time for looped animations.
Apply(skeleton, lastTime, int.MaxValue, alpha, firedEvents);
lastTime = 0;
}
int frameIndex;
if (frameCount == 1)
frameIndex = 0;
else {
frameIndex = Animation.binarySearch(frames, lastTime, 1);
float frame = frames[frameIndex];
while (frameIndex > 0) {
float lastFrame = frames[frameIndex - 1];
// Fire multiple events with the same frame and events that occurred at lastTime.
if (lastFrame != frame && lastFrame != lastTime) break;
frameIndex--;
}
}
for (; frameIndex < frameCount && time > frames[frameIndex]; frameIndex++)
firedEvents.Add(Events[frameIndex]);
}
}
public class DrawOrderTimeline : Timeline {
public float[] Frames { get; private set; } // time, ...
public int[][] DrawOrders { get; private set; }
@ -441,7 +512,7 @@ namespace Spine {
DrawOrders[frameIndex] = drawOrder;
}
public void Apply (Skeleton skeleton, float time, float alpha) {
public void Apply (Skeleton skeleton, float lastTime, float time, float alpha, List<Event> firedEvents) {
float[] frames = Frames;
if (time < frames[0]) return; // Time is before first frame.

View File

@ -38,28 +38,55 @@ namespace Spine {
public class AnimationState {
public AnimationStateData Data { get; private set; }
public Animation Animation { get; private set; }
public float Time { get; set; }
private float time;
public float Time {
get { return time; }
set {
time = value;
currentLastTime = value - 0.00001f;
}
}
private float currentLastTime;
public bool Loop { get; set; }
private Animation previous;
private float previousTime;
private bool previousLoop;
private QueueEntry currentQueueEntry;
private float mixTime, mixDuration;
private List<Event> events = new List<Event>();
private List<QueueEntry> queue = new List<QueueEntry>();
public event EventHandler Start;
public event EventHandler End;
public event EventHandler<EventTriggeredArgs> Event;
public event EventHandler<CompleteArgs> Complete;
public AnimationState (AnimationStateData data) {
if (data == null) throw new ArgumentNullException("data cannot be null.");
Data = data;
}
public void Update (float delta) {
Time += delta;
time += delta;
previousTime += delta;
mixTime += delta;
if (Animation != null) {
float duration = Animation.Duration;
if (Loop ? (currentLastTime % duration > time % duration)
: (currentLastTime < duration && time >= duration)) {
int count = (int)(time / duration);
if (currentQueueEntry != null) currentQueueEntry.OnComplete(this, count);
if (Complete != null) Complete(this, new CompleteArgs(count));
}
}
if (queue.Count > 0) {
QueueEntry entry = queue[0];
if (Time >= entry.delay) {
SetAnimationInternal(entry.animation, entry.loop);
if (time >= entry.delay) {
SetAnimationInternal(entry.animation, entry.loop, entry);
queue.RemoveAt(0);
}
}
@ -67,35 +94,94 @@ namespace Spine {
public void Apply (Skeleton skeleton) {
if (Animation == null) return;
List<Event> events = this.events;
events.Clear();
if (previous != null) {
previous.Apply(skeleton, previousTime, previousLoop);
previous.Apply(skeleton, int.MaxValue, previousTime, previousLoop, null);
float alpha = mixTime / mixDuration;
if (alpha >= 1) {
alpha = 1;
previous = null;
}
Animation.Mix(skeleton, Time, Loop, alpha);
Animation.Mix(skeleton, currentLastTime, time, Loop, events, alpha);
} else
Animation.Apply(skeleton, Time, Loop);
Animation.Apply(skeleton, currentLastTime, time, Loop, events);
if (Event != null || currentQueueEntry != null) {
foreach (Event e in events) {
if (currentQueueEntry != null) currentQueueEntry.OnEvent(this, e);
if (Event != null) Event(this, new EventTriggeredArgs(e));
}
}
public void AddAnimation (String animationName, bool loop) {
AddAnimation(animationName, loop, 0);
currentLastTime = time;
}
public void AddAnimation (String animationName, bool loop, float delay) {
public void ClearAnimation () {
previous = null;
Animation = null;
queue.Clear();
}
private void SetAnimationInternal (Animation animation, bool loop, QueueEntry entry) {
previous = null;
if (Animation != null) {
if (currentQueueEntry != null) currentQueueEntry.OnEnd(this);
if (End != null) End(this, EventArgs.Empty);
if (animation != null) {
mixDuration = Data.GetMix(Animation, animation);
if (mixDuration > 0) {
mixTime = 0;
previous = Animation;
previousTime = time;
previousLoop = Loop;
}
}
}
Animation = animation;
Loop = loop;
time = 0;
currentLastTime = 0;
currentQueueEntry = entry;
if (currentQueueEntry != null) currentQueueEntry.OnStart(this);
if (Start != null) Start(this, EventArgs.Empty);
}
public void SetAnimation (String animationName, bool loop) {
Animation animation = Data.SkeletonData.FindAnimation(animationName);
if (animation == null) throw new ArgumentException("Animation not found: " + animationName);
AddAnimation(animation, loop, delay);
SetAnimation(animation, loop);
}
public void AddAnimation (Animation animation, bool loop) {
AddAnimation(animation, loop, 0);
/** Set the current animation. Any queued animations are cleared and the current animation time is set to 0.
* @param animation May be null.
* @param listener May be null. */
public void SetAnimation (Animation animation, bool loop) {
queue.Clear();
SetAnimationInternal(animation, loop, null);
}
public QueueEntry AddAnimation (String animationName, bool loop) {
return AddAnimation(animationName, loop, 0);
}
public QueueEntry AddAnimation (String animationName, bool loop, float delay) {
Animation animation = Data.SkeletonData.FindAnimation(animationName);
if (animation == null) throw new ArgumentException("Animation not found: " + animationName);
return AddAnimation(animation, loop, delay);
}
public QueueEntry AddAnimation (Animation animation, bool loop) {
return AddAnimation(animation, loop, 0);
}
/** Adds an animation to be played delay seconds after the current or last queued animation.
* @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */
public void AddAnimation (Animation animation, bool loop, float delay) {
public QueueEntry AddAnimation (Animation animation, bool loop, float delay) {
QueueEntry entry = new QueueEntry();
entry.animation = animation;
entry.loop = loop;
@ -110,54 +196,59 @@ namespace Spine {
entry.delay = delay;
queue.Add(entry);
}
private void SetAnimationInternal (Animation animation, bool loop) {
previous = null;
if (animation != null && Animation != null) {
mixDuration = Data.GetMix(Animation, animation);
if (mixDuration > 0) {
mixTime = 0;
previous = Animation;
previousTime = Time;
previousLoop = Loop;
}
}
Animation = animation;
Loop = loop;
Time = 0;
}
public void SetAnimation (String animationName, bool loop) {
Animation animation = Data.SkeletonData.FindAnimation(animationName);
if (animation == null) throw new ArgumentException("Animation not found: " + animationName);
SetAnimation(animation, loop);
}
public void SetAnimation (Animation animation, bool loop) {
queue.Clear();
SetAnimationInternal(animation, loop);
}
public void ClearAnimation () {
previous = null;
Animation = null;
queue.Clear();
return entry;
}
/** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */
public bool IsComplete () {
return Animation == null || Time >= Animation.Duration;
return Animation == null || time >= Animation.Duration;
}
override public String ToString () {
return (Animation != null && Animation.Name != null) ? Animation.Name : base.ToString();
}
}
public class EventTriggeredArgs : EventArgs {
public Event Event { get; private set; }
public EventTriggeredArgs (Event e) {
Event = e;
}
}
class QueueEntry {
public Spine.Animation animation;
public bool loop;
public float delay;
public class CompleteArgs : EventArgs {
public int LoopCount { get; private set; }
public CompleteArgs (int loopCount) {
LoopCount = loopCount;
}
}
public class QueueEntry {
internal Spine.Animation animation;
internal bool loop;
internal float delay;
public event EventHandler Start;
public event EventHandler End;
public event EventHandler<EventTriggeredArgs> Event;
public event EventHandler<CompleteArgs> Complete;
internal void OnStart (AnimationState state) {
if (Start != null) Start(state, EventArgs.Empty);
}
internal void OnEnd (AnimationState state) {
if (End != null) End(state, EventArgs.Empty);
}
internal void OnEvent (AnimationState state, Event e) {
if (Event != null) Event(state, new EventTriggeredArgs(e));
}
internal void OnComplete (AnimationState state, int loopCount) {
if (Complete != null) Complete(state, new CompleteArgs(loopCount));
}
}
}

51
spine-csharp/src/Event.cs Normal file
View File

@ -0,0 +1,51 @@
/******************************************************************************
* Spine Runtime Software License - Version 1.0
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* Redistribution and use in source and binary forms in whole or in part, with
* or without modification, are permitted provided that the following conditions
* are met:
*
* 1. A Spine Single User License or Spine Professional License must be
* purchased from Esoteric Software and the license must remain valid:
* http://esotericsoftware.com/
* 2. Redistributions of source code must retain this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer.
* 3. Redistributions in binary form must reproduce this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer, in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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;
namespace Spine {
public class Event {
public EventData Data { get; private set; }
public int Int { get; set; }
public float Float { get; set; }
public String String { get; set; }
public Event (EventData data) {
Data = data;
}
override public String ToString () {
return Data.Name;
}
}
}

View File

@ -0,0 +1,52 @@
/******************************************************************************
* Spine Runtime Software License - Version 1.0
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* Redistribution and use in source and binary forms in whole or in part, with
* or without modification, are permitted provided that the following conditions
* are met:
*
* 1. A Spine Single User License or Spine Professional License must be
* purchased from Esoteric Software and the license must remain valid:
* http://esotericsoftware.com/
* 2. Redistributions of source code must retain this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer.
* 3. Redistributions in binary form must reproduce this license, which is the
* above copyright notice, this declaration of conditions and the following
* disclaimer, in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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;
namespace Spine {
public class EventData {
public String Name { get; private set; }
public int Int { get; set; }
public float Float { get; set; }
public String String { get; set; }
public EventData (String name) {
if (name == null) throw new ArgumentNullException("name cannot be null.");
Name = name;
}
override public String ToString () {
return Name;
}
}
}

View File

@ -133,8 +133,10 @@ namespace Spine {
} else
polygon = new Polygon();
polygons.Add(polygon);
polygon.Count = boundingBox.Vertices.Length;
if (polygon.Vertices.Length < polygon.Count) polygon.Vertices = new float[polygon.Count];
int count = boundingBox.Vertices.Length;
polygon.Count = count;
if (polygon.Vertices.Length < count) polygon.Vertices = new float[count];
boundingBox.ComputeWorldVertices(x, y, slot.Bone, polygon.Vertices);
}
}

View File

@ -42,12 +42,14 @@ namespace Spine {
public List<Skin> Skins { get; private set; }
/** May be null. */
public Skin DefaultSkin;
public List<EventData> Events { get; private set; }
public List<Animation> Animations { get; private set; }
public SkeletonData () {
Bones = new List<BoneData>();
Slots = new List<SlotData>();
Skins = new List<Skin>();
Events = new List<EventData>();
Animations = new List<Animation>();
}
@ -117,6 +119,21 @@ namespace Spine {
return null;
}
// --- Events.
public void AddEvent (EventData eventData) {
if (eventData == null) throw new ArgumentNullException("eventData cannot be null.");
Events.Add(eventData);
}
/** @return May be null. */
public EventData findEvent (String eventDataName) {
if (eventDataName == null) throw new ArgumentNullException("eventDataName cannot be null.");
foreach (EventData eventData in Events)
if (eventData.Name == eventDataName) return eventData;
return null;
}
// --- Animations.
public void AddAnimation (Animation animation) {

View File

@ -118,8 +118,7 @@ namespace Spine {
// Slots.
if (root.ContainsKey("slots")) {
var slots = (List<Object>)root["slots"];
foreach (Dictionary<String, Object> slotMap in slots) {
foreach (Dictionary<String, Object> slotMap in (List<Object>)root["slots"]) {
String slotName = (String)slotMap["name"];
String boneName = (String)slotMap["bone"];
BoneData boneData = skeletonData.FindBone(boneName);
@ -147,8 +146,7 @@ namespace Spine {
// Skins.
if (root.ContainsKey("skins")) {
var skinMap = (Dictionary<String, Object>)root["skins"];
foreach (KeyValuePair<String, Object> entry in skinMap) {
foreach (KeyValuePair<String, Object> entry in (Dictionary<String, Object>)root["skins"]) {
Skin skin = new Skin(entry.Key);
foreach (KeyValuePair<String, Object> slotEntry in (Dictionary<String, Object>)entry.Value) {
int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key);
@ -163,11 +161,21 @@ namespace Spine {
}
}
// Events.
if (root.ContainsKey("events")) {
foreach (KeyValuePair<String, Object> entry in (Dictionary<String, Object>)root["events"]) {
var entryMap = (Dictionary<String, Object>)entry.Value;
EventData eventData = new EventData(entry.Key);
eventData.Int = GetInt(entryMap, "int", 0);
eventData.Float = GetFloat(entryMap, "float", 0);
eventData.String = GetString(entryMap, "string", null);
skeletonData.AddEvent(eventData);
}
}
// Animations.
if (root.ContainsKey("animations")) {
var animationMap = (Dictionary<String, Object>)root["animations"];
foreach (KeyValuePair<String, Object> entry in animationMap)
foreach (KeyValuePair<String, Object> entry in (Dictionary<String, Object>)root["animations"])
ReadAnimation(entry.Key, (Dictionary<String, Object>)entry.Value, skeletonData);
}
@ -213,16 +221,28 @@ namespace Spine {
private float GetFloat (Dictionary<String, Object> map, String name, float defaultValue) {
if (!map.ContainsKey(name))
return (float)defaultValue;
return defaultValue;
return (float)map[name];
}
private int GetInt (Dictionary<String, Object> map, String name, int defaultValue) {
if (!map.ContainsKey(name))
return defaultValue;
return (int)map[name];
}
private bool GetBoolean (Dictionary<String, Object> map, String name, bool defaultValue) {
if (!map.ContainsKey(name))
return (bool)defaultValue;
return defaultValue;
return (bool)map[name];
}
private String GetString (Dictionary<String, Object> map, String name, String defaultValue) {
if (!map.ContainsKey(name))
return defaultValue;
return (String)map[name];
}
public static float ToColor (String hexString, int colorIndex) {
if (hexString.Length != 8)
throw new ArgumentException("Color hexidecimal length must be 8, recieved: " + hexString);
@ -234,8 +254,7 @@ namespace Spine {
float duration = 0;
if (map.ContainsKey("bones")) {
var bonesMap = (Dictionary<String, Object>)map["bones"];
foreach (KeyValuePair<String, Object> entry in bonesMap) {
foreach (KeyValuePair<String, Object> entry in (Dictionary<String, Object>)map["bones"]) {
String boneName = entry.Key;
int boneIndex = skeletonData.FindBoneIndex(boneName);
if (boneIndex == -1)
@ -289,8 +308,7 @@ namespace Spine {
}
if (map.ContainsKey("slots")) {
var slotsMap = (Dictionary<String, Object>)map["slots"];
foreach (KeyValuePair<String, Object> entry in slotsMap) {
foreach (KeyValuePair<String, Object> entry in (Dictionary<String, Object>)map["slots"]) {
String slotName = entry.Key;
int slotIndex = skeletonData.FindSlotIndex(slotName);
var timelineMap = (Dictionary<String, Object>)entry.Value;
@ -331,6 +349,23 @@ namespace Spine {
}
}
if (map.ContainsKey("events")) {
var eventsMap = (List<Object>)map["events"];
EventTimeline timeline = new EventTimeline(eventsMap.Count);
int frameIndex = 0;
foreach (Dictionary<String, Object> eventMap in eventsMap) {
EventData eventData = skeletonData.findEvent((String)eventMap["name"]);
if (eventData == null) throw new Exception("Event not found: " + eventMap["name"]);
Event e = new Event(eventData);
e.Int = GetInt(eventMap, "int", eventData.Int);
e.Float = GetFloat(eventMap, "float", eventData.Float);
e.String = GetString(eventMap, "string", eventData.String);
timeline.setFrame(frameIndex++, (float)eventMap["time"], e);
}
timelines.Add(timeline);
duration = Math.Max(duration, timeline.Frames[timeline.FrameCount - 1]);
}
if (map.ContainsKey("draworder")) {
var values = (List<Object>)map["draworder"];
DrawOrderTimeline timeline = new DrawOrderTimeline(values.Count);

View File

@ -86,6 +86,11 @@ namespace Spine {
}
state = new AnimationState(stateData);
state.Start += new EventHandler(Start);
state.End += new EventHandler(End);
state.Complete += new EventHandler<CompleteArgs>(Complete);
state.Event += new EventHandler<EventTriggeredArgs>(Event);
if (true) {
state.SetAnimation("drawOrder", true);
} else {
@ -140,5 +145,21 @@ namespace Spine {
base.Draw(gameTime);
}
public void Start (object sender, EventArgs e) {
Console.WriteLine("start");
}
public void End (object sender, EventArgs e) {
Console.WriteLine("end");
}
public void Complete (object sender, CompleteArgs e) {
Console.WriteLine("complete " + e.LoopCount);
}
public void Event (object sender, EventTriggeredArgs e) {
Console.WriteLine("event " + e.Event);
}
}
}