diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java index ea5d06296..691ca2c13 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/AnimationStateTest.java @@ -114,91 +114,91 @@ public class AnimationStateTest { stateData = new AnimationStateData(skeletonData); setup( // 1 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 0.5f, 0.5f), // - expect("event 30", 0, 1, 1), // - expect("complete 1", 0, 1, 1), // - expect("end", 0, 1, 1.1f) // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 0.5f, 0.5f), // + expect(0, "event 30", 1, 1), // + expect(0, "complete 1", 1, 1), // + expect(0, "end", 1, 1.1f) // ); state.setAnimation(0, "events1", false); run(0.1f, 1000); setup( // 2 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 0.467f, 0.467f), // - expect("event 30", 0, 1.017f, 1.017f), // - expect("complete 1", 0, 1.017f, 1.017f), // - expect("end", 0, 1.017f, 1.033f) // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 0.467f, 0.467f), // + expect(0, "event 30", 1.017f, 1.017f), // + expect(0, "complete 1", 1.017f, 1.017f), // + expect(0, "end", 1.017f, 1.033f) // ); state.setAnimation(0, "events1", false); run(1 / 60f, 1000); setup( // 3 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 30, 30), // - expect("event 30", 0, 30, 30), // - expect("complete 1", 0, 30, 30), // - expect("end", 0, 30, 60) // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 30, 30), // + expect(0, "event 30", 30, 30), // + expect(0, "complete 1", 30, 30), // + expect(0, "end", 30, 60) // ); state.setAnimation(0, "events1", false); run(30, 1000); setup( // 4 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 1, 1), // - expect("event 30", 0, 1, 1), // - expect("complete 1", 0, 1, 1), // - expect("end", 0, 1, 2) // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 1, 1), // + expect(0, "event 30", 1, 1), // + expect(0, "complete 1", 1, 1), // + expect(0, "end", 1, 2) // ); state.setAnimation(0, "events1", false); run(1, 1.01f); setup( // 5 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 0.5f, 0.5f), // - expect("event 30", 0, 1, 1), // - expect("complete 1", 0, 1, 1), // - expect("event 0", 0, 1, 1), // - expect("event 14", 0, 1.5f, 1.5f), // - expect("event 30", 0, 2, 2), // - expect("complete 2", 0, 2, 2), // - expect("event 0", 0, 2, 2) // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 0.5f, 0.5f), // + expect(0, "event 30", 1, 1), // + expect(0, "complete 1", 1, 1), // + expect(0, "event 0", 1, 1), // + expect(0, "event 14", 1.5f, 1.5f), // + expect(0, "event 30", 2, 2), // + expect(0, "complete 2", 2, 2), // + expect(0, "event 0", 2, 2) // ); state.setAnimation(0, "events1", true); run(0.1f, 2.3f); setup( // 6 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 0.5f, 0.5f), // - expect("event 30", 0, 1, 1), // - expect("complete 1", 0, 1, 1), // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 0.5f, 0.5f), // + expect(0, "event 30", 1, 1), // + expect(0, "complete 1", 1, 1), // - expect("start", 1, 0.1f, 1.1f), // + expect(1, "start", 0.1f, 1.1f), // - expect("interrupt", 0, 1.1f, 1.1f), // - expect("end", 0, 1.1f, 1.1f), // + expect(0, "interrupt", 1.1f, 1.1f), // + expect(0, "end", 1.1f, 1.1f), // - expect("event 0", 1, 0.1f, 1.1f), // - expect("event 14", 1, 0.5f, 1.5f), // - expect("event 30", 1, 1, 2), // - expect("complete 1", 1, 1, 2), // + expect(1, "event 0", 0.1f, 1.1f), // + expect(1, "event 14", 0.5f, 1.5f), // + expect(1, "event 30", 1, 2), // + expect(1, "complete 1", 1, 2), // - expect("start", 0, 0.1f, 2.1f), // + expect(0, "start", 0.1f, 2.1f), // - expect("interrupt", 1, 1.1f, 2.1f), // - expect("end", 1, 1.1f, 2.1f), // + expect(1, "interrupt", 1.1f, 2.1f), // + expect(1, "end", 1.1f, 2.1f), // - expect("event 0", 0, 0.1f, 2.1f), // - expect("event 14", 0, 0.5f, 2.5f), // - expect("event 30", 0, 1, 3), // - expect("complete 1", 0, 1, 3), // - expect("end", 0, 1, 3.1f) // + expect(0, "event 0", 0.1f, 2.1f), // + expect(0, "event 14", 0.5f, 2.5f), // + expect(0, "event 30", 1, 3), // + expect(0, "complete 1", 1, 3), // + expect(0, "end", 1, 3.1f) // ); state.setAnimation(0, "events1", false); state.addAnimation(0, "events2", false, 0); @@ -206,52 +206,123 @@ public class AnimationStateTest { run(0.1f, 4f); setup( // 7 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 0.5f, 0.5f), // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 0.5f, 0.5f), // - expect("start", 1, 0.1f, 0.6f), // + expect(1, "start", 0.1f, 0.6f), // - expect("interrupt", 0, 0.6f, 0.6f), // - expect("end", 0, 0.6f, 0.6f), // + expect(0, "interrupt", 0.6f, 0.6f), // + expect(0, "end", 0.6f, 0.6f), // - expect("event 0", 1, 0.1f, 0.6f), // - expect("event 14", 1, 0.5f, 1.0f), // - expect("event 30", 1, 1, 1.5f), // - expect("complete 1", 1, 1, 1.5f), // - expect("end", 1, 1, 1.6f) // + expect(1, "event 0", 0.1f, 0.6f), // + expect(1, "event 14", 0.5f, 1.0f), // + expect(1, "event 30", 1, 1.5f), // + expect(1, "complete 1", 1, 1.5f), // + expect(1, "end", 1, 1.6f) // ); state.setAnimation(0, "events1", false); state.addAnimation(0, "events2", false, 0.5f); run(0.1f, 1000); setup( // 8 - expect("start", 0, 0, 0), // - expect("event 0", 0, 0, 0), // - expect("event 14", 0, 0.5f, 0.5f), // + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + expect(0, "event 14", 0.5f, 0.5f), // - expect("start", 1, 0.1f, 1), // + expect(1, "start", 0.1f, 1), // - expect("interrupt", 0, 1, 1), // - expect("event 30", 0, 1, 1), // - expect("complete 1", 0, 1, 1), // - expect("event 0", 0, 1, 1), // + expect(0, "interrupt", 1, 1), // + expect(0, "event 30", 1, 1), // + expect(0, "complete 1", 1, 1), // + expect(0, "event 0", 1, 1), // - expect("event 0", 1, 0.1f, 1), // - expect("event 14", 1, 0.5f, 1.4f), // + expect(1, "event 0", 0.1f, 1), // + expect(1, "event 14", 0.5f, 1.4f), // - expect("event 14", 0, 1.5f, 1.5f), // - expect("end", 0, 1.6f, 1.6f), // + expect(0, "event 14", 1.5f, 1.5f), // + expect(0, "end", 1.6f, 1.6f), // - expect("event 30", 1, 1, 1.9f), // - expect("complete 1", 1, 1, 1.9f), // - expect("end", 1, 1, 2) // + expect(1, "event 30", 1, 1.9f), // + expect(1, "complete 1", 1, 1.9f), // + expect(1, "end", 1, 2) // ); stateData.setMix("events1", "events2", 0.7f); state.setAnimation(0, "events1", true); state.addAnimation(0, "events2", false, 0.9f); run(0.1f, 1000); + setup( // 9, first animation's events fire during mix + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + + expect(1, "start", 0.1f, 0.5f), // + + expect(0, "interrupt", 0.5f, 0.5f), // + expect(0, "event 14", 0.5f, 0.5f), // + + expect(1, "event 0", 0.1f, 0.5f), // + expect(1, "event 14", 0.5f, 0.9f), // + + expect(0, "event 30", 1, 1), // + expect(0, "complete 1", 1, 1), // + expect(0, "end", 1.1f, 1.1f), // + + expect(1, "event 30", 1, 1.4f), // + expect(1, "complete 1", 1, 1.4f), // + expect(1, "end", 1, 1.5f) // + ); + state.setAnimation(0, "events1", false); + state.addAnimation(0, "events2", false, 0.4f); + run(0.1f, 1000); + + setup( // 10, only some of first animation's events fire during mix due to event threshold + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + + expect(1, "start", 0.1f, 0.5f), // + + expect(0, "interrupt", 0.5f, 0.5f), // + expect(0, "event 14", 0.5f, 0.5f), // + + expect(1, "event 0", 0.1f, 0.5f), // + expect(1, "event 14", 0.5f, 0.9f), // + + expect(0, "complete 1", 1, 1), // + expect(0, "end", 1.1f, 1.1f), // + + expect(1, "event 30", 1, 1.4f), // + expect(1, "complete 1", 1, 1.4f), // + expect(1, "end", 1, 1.5f) // + ); + state.setDefaultEventThreshold(0.5f); + state.setAnimation(0, "events1", false); + state.addAnimation(0, "events2", false, 0.4f); + run(0.1f, 1000); + + setup( // 11, first animation's events do not fire during mix due to event threshold + expect(0, "start", 0, 0), // + expect(0, "event 0", 0, 0), // + + expect(1, "start", 0.1f, 0.5f), // + + expect(0, "interrupt", 0.5f, 0.5f), // + + expect(1, "event 0", 0.1f, 0.5f), // + expect(1, "event 14", 0.5f, 0.9f), // + + expect(0, "complete 1", 1, 1), // + expect(0, "end", 1.1f, 1.1f), // + + expect(1, "event 30", 1, 1.4f), // + expect(1, "complete 1", 1, 1.4f), // + expect(1, "end", 1, 1.5f) // + ); + state.setDefaultEventThreshold(0f); + state.setAnimation(0, "events1", false); + state.addAnimation(0, "events2", false, 0.4f); + run(0.1f, 1000); + System.out.println("AnimationState tests passed."); } @@ -285,7 +356,7 @@ public class AnimationStateTest { System.out.println(buffer); } - Result expect (String name, int animationIndex, float trackTime, float totalTime) { + Result expect (int animationIndex, String name, float trackTime, float totalTime) { Result result = new Result(); result.name = name; result.animationIndex = animationIndex; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index 9e15dd1fa..a8f54ed1b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -44,6 +44,7 @@ public class AnimationState { private final EventQueue queue = new EventQueue(); final Array listeners = new Array(); private float timeScale = 1; + private float defaultEventThreshold = 1; final Pool trackEntryPool = new Pool() { protected Object newObject () { @@ -108,13 +109,15 @@ public class AnimationState { TrackEntry previous = current.previous; if (previous != null) { + mix *= current.mixTime / current.mixDuration; + Array previousEvents = mix < previous.eventThreshold ? events : null; + float previousTime = previous.time; if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; - previous.animation.mix(skeleton, previous.lastTime, previousTime, previous.loop, events, previous.mix); + previous.animation.mix(skeleton, previous.lastTime, previousTime, previous.loop, previousEvents, previous.mix); queueEvents(previous, previous.lastTime, previousTime, previous.endTime); previous.lastTime = previousTime; - mix *= current.mixTime / current.mixDuration; if (mix >= 1) { mix = 1; queue.end(current.previous); @@ -236,6 +239,8 @@ public class AnimationState { entry.animation = animation; entry.loop = loop; entry.endTime = animation.getDuration(); + entry.eventThreshold = defaultEventThreshold; + setCurrent(trackIndex, entry); queue.drain(); return entry; @@ -255,6 +260,7 @@ public class AnimationState { entry.animation = animation; entry.loop = loop; entry.endTime = animation.getDuration(); + entry.eventThreshold = defaultEventThreshold; TrackEntry last = expandToIndex(trackIndex); if (last != null) { @@ -308,6 +314,14 @@ public class AnimationState { this.timeScale = timeScale; } + public float getDefaultEventThreshold () { + return defaultEventThreshold; + } + + public void setDefaultEventThreshold (float defaultEventThreshold) { + this.defaultEventThreshold = defaultEventThreshold; + } + public AnimationStateData getData () { return data; } @@ -338,7 +352,7 @@ public class AnimationState { TrackEntry next, previous; Animation animation; boolean loop; - float delay, time, lastTime = -1, endTime, timeScale = 1; + float delay, time, lastTime = -1, endTime, timeScale = 1, eventThreshold; float mixTime, mixDuration; AnimationStateListener listener; float mix = 1; @@ -425,6 +439,14 @@ public class AnimationState { this.timeScale = timeScale; } + public float getEventThreshold () { + return eventThreshold; + } + + public void setEventThreshold (float eventThreshold) { + this.eventThreshold = eventThreshold; + } + public TrackEntry getNext () { return next; }