AnimationState, added attachment threshold. Defaults changed to NOT apply attachment timelines or fire events for an animation being mixed out.

#621
This commit is contained in:
NathanSweet 2016-08-18 14:46:15 +02:00
parent b020bc0d44
commit cc4f19da98
3 changed files with 64 additions and 26 deletions

View File

@ -233,14 +233,11 @@ public class AnimationStateTest {
expect(1, "start", 0.1f, 1), // expect(1, "start", 0.1f, 1), //
expect(0, "interrupt", 1, 1), // expect(0, "interrupt", 1, 1), //
expect(0, "event 30", 1, 1), //
expect(0, "complete 1", 1, 1), // expect(0, "complete 1", 1, 1), //
expect(0, "event 0", 1, 1), //
expect(1, "event 0", 0.1f, 1), // expect(1, "event 0", 0.1f, 1), //
expect(1, "event 14", 0.5f, 1.4f), // expect(1, "event 14", 0.5f, 1.4f), //
expect(0, "event 14", 1.5f, 1.5f), //
expect(0, "end", 1.6f, 1.6f), // expect(0, "end", 1.6f, 1.6f), //
expect(1, "event 30", 1, 1.9f), // expect(1, "event 30", 1, 1.9f), //
@ -259,12 +256,10 @@ public class AnimationStateTest {
expect(1, "start", 0.1f, 0.5f), // expect(1, "start", 0.1f, 0.5f), //
expect(0, "interrupt", 0.5f, 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 0", 0.1f, 0.5f), //
expect(1, "event 14", 0.5f, 0.9f), // expect(1, "event 14", 0.5f, 0.9f), //
expect(0, "event 30", 1, 1), //
expect(0, "complete 1", 1, 1), // expect(0, "complete 1", 1, 1), //
expect(0, "end", 1.1f, 1.1f), // expect(0, "end", 1.1f, 1.1f), //
@ -307,10 +302,12 @@ public class AnimationStateTest {
expect(1, "start", 0.1f, 0.5f), // expect(1, "start", 0.1f, 0.5f), //
expect(0, "interrupt", 0.5f, 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 0", 0.1f, 0.5f), //
expect(1, "event 14", 0.5f, 0.9f), // expect(1, "event 14", 0.5f, 0.9f), //
expect(0, "event 30", 1, 1), //
expect(0, "complete 1", 1, 1), // expect(0, "complete 1", 1, 1), //
expect(0, "end", 1.1f, 1.1f), // expect(0, "end", 1.1f, 1.1f), //
@ -318,7 +315,7 @@ public class AnimationStateTest {
expect(1, "complete 1", 1, 1.4f), // expect(1, "complete 1", 1, 1.4f), //
expect(1, "end", 1, 1.5f) // expect(1, "end", 1, 1.5f) //
); );
state.setDefaultEventThreshold(0f); state.setDefaultEventThreshold(1);
state.setAnimation(0, "events1", false); state.setAnimation(0, "events1", false);
state.addAnimation(0, "events2", false, 0.4f); state.addAnimation(0, "events2", false, 0.4f);
run(0.1f, 1000); run(0.1f, 1000);
@ -334,7 +331,7 @@ public class AnimationStateTest {
time = 0; time = 0;
fail = false; fail = false;
buffer.setLength(0); buffer.setLength(0);
buffer.append(String.format("%-12s%-8s%-8s%-8s%s\n", "", "anim", "track", "total", "result")); buffer.append(String.format("%-12s%-8s%-8s%-8s%s\n", "#" + test, "anim", "track", "total", "result"));
} }
void run (float incr, float endTime) { void run (float incr, float endTime) {
@ -349,8 +346,8 @@ public class AnimationStateTest {
actual.clear(); actual.clear();
expected.clear(); expected.clear();
if (fail) { if (fail) {
System.out.println("Test failed: " + test);
System.out.println(buffer); System.out.println(buffer);
System.out.println("TEST FAILED!");
System.exit(0); System.exit(0);
} }
System.out.println(buffer); System.out.println(buffer);

View File

@ -40,8 +40,8 @@ import com.esotericsoftware.spine.attachments.VertexAttachment;
public class Animation { public class Animation {
final String name; final String name;
private final Array<Timeline> timelines; final Array<Timeline> timelines;
private float duration; float duration;
public Animation (String name, Array<Timeline> timelines, float duration) { public Animation (String name, Array<Timeline> timelines, float duration) {
if (name == null) throw new IllegalArgumentException("name cannot be null."); if (name == null) throw new IllegalArgumentException("name cannot be null.");

View File

@ -35,6 +35,8 @@ import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntArray; import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.Pool; import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.Pool.Poolable; import com.badlogic.gdx.utils.Pool.Poolable;
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
/** Stores state for an animation and automatically mixes between animations. */ /** Stores state for an animation and automatically mixes between animations. */
public class AnimationState { public class AnimationState {
@ -44,7 +46,7 @@ public class AnimationState {
private final EventQueue queue = new EventQueue(); private final EventQueue queue = new EventQueue();
final Array<AnimationStateListener> listeners = new Array(); final Array<AnimationStateListener> listeners = new Array();
private float timeScale = 1; private float timeScale = 1;
private float defaultEventThreshold = 1; private float defaultEventThreshold, defaultAttachmentThreshold;
final Pool<TrackEntry> trackEntryPool = new Pool() { final Pool<TrackEntry> trackEntryPool = new Pool() {
protected Object newObject () { protected Object newObject () {
@ -103,21 +105,13 @@ public class AnimationState {
TrackEntry current = tracks.get(i); TrackEntry current = tracks.get(i);
if (current == null) continue; if (current == null) continue;
float time = current.time, lastTime = current.lastTime, endTime = current.endTime, mix = current.mix; float time = current.time, lastTime = current.lastTime, endTime = current.endTime, mix = current.alpha;
boolean loop = current.loop; boolean loop = current.loop;
if (!loop && time > endTime) time = endTime; if (!loop && time > endTime) time = endTime;
TrackEntry previous = current.previous; if (current.previous != null) {
if (previous != null) {
mix *= current.mixTime / current.mixDuration; mix *= current.mixTime / current.mixDuration;
Array<Event> previousEvents = mix < previous.eventThreshold ? events : null; applyPrevious(current.previous, skeleton, mix);
float previousTime = previous.time;
if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime;
previous.animation.mix(skeleton, previous.lastTime, previousTime, previous.loop, previousEvents, previous.mix);
queueEvents(previous, previous.lastTime, previousTime, previous.endTime);
previous.lastTime = previousTime;
if (mix >= 1) { if (mix >= 1) {
mix = 1; mix = 1;
queue.end(current.previous); queue.end(current.previous);
@ -133,6 +127,35 @@ public class AnimationState {
queue.drain(); queue.drain();
} }
private void applyPrevious (TrackEntry previous, Skeleton skeleton, float mix) {
float previousTime = previous.time;
if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime;
float lastTime = previous.lastTime, time = previousTime, alpha = previous.alpha;
Animation animation = previous.animation;
if (previous.loop && animation.duration != 0) {
time %= animation.duration;
if (lastTime > 0) lastTime %= animation.duration;
}
Array<Event> events = mix < previous.eventThreshold ? this.events : null;
Array<Timeline> timelines = animation.timelines;
if (mix < previous.attachmentThreshold) {
for (int i = 0, n = timelines.size; i < n; i++)
timelines.get(i).apply(skeleton, lastTime, time, events, alpha);
} else {
for (int i = 0, n = timelines.size; i < n; i++) {
Timeline timeline = timelines.get(i);
if (timeline instanceof AttachmentTimeline) continue;
timeline.apply(skeleton, lastTime, time, events, alpha);
}
}
queueEvents(previous, previous.lastTime, previousTime, previous.endTime);
previous.lastTime = previousTime;
}
private void queueEvents (TrackEntry entry, float lastTime, float time, float endTime) { private void queueEvents (TrackEntry entry, float lastTime, float time, float endTime) {
Array<Event> events = this.events; Array<Event> events = this.events;
int n = events.size; int n = events.size;
@ -240,6 +263,7 @@ public class AnimationState {
entry.loop = loop; entry.loop = loop;
entry.endTime = animation.getDuration(); entry.endTime = animation.getDuration();
entry.eventThreshold = defaultEventThreshold; entry.eventThreshold = defaultEventThreshold;
entry.attachmentThreshold = defaultAttachmentThreshold;
setCurrent(trackIndex, entry); setCurrent(trackIndex, entry);
queue.drain(); queue.drain();
@ -261,6 +285,7 @@ public class AnimationState {
entry.loop = loop; entry.loop = loop;
entry.endTime = animation.getDuration(); entry.endTime = animation.getDuration();
entry.eventThreshold = defaultEventThreshold; entry.eventThreshold = defaultEventThreshold;
entry.attachmentThreshold = defaultAttachmentThreshold;
TrackEntry last = expandToIndex(trackIndex); TrackEntry last = expandToIndex(trackIndex);
if (last != null) { if (last != null) {
@ -322,6 +347,14 @@ public class AnimationState {
this.defaultEventThreshold = defaultEventThreshold; this.defaultEventThreshold = defaultEventThreshold;
} }
public float getDefaultAttachmentThreshold () {
return defaultAttachmentThreshold;
}
public void setDefaultAttachmentThreshold (float defaultAttachmentThreshold) {
this.defaultAttachmentThreshold = defaultAttachmentThreshold;
}
public AnimationStateData getData () { public AnimationStateData getData () {
return data; return data;
} }
@ -352,10 +385,10 @@ public class AnimationState {
TrackEntry next, previous; TrackEntry next, previous;
Animation animation; Animation animation;
boolean loop; boolean loop;
float delay, time, lastTime = -1, endTime, timeScale = 1, eventThreshold; float delay, time, lastTime = -1, endTime, timeScale = 1, eventThreshold, attachmentThreshold;
float mixTime, mixDuration; float mixTime, mixDuration;
AnimationStateListener listener; AnimationStateListener listener;
float mix = 1; float alpha = 1;
public void reset () { public void reset () {
next = null; next = null;
@ -424,11 +457,11 @@ public class AnimationState {
} }
public float getMix () { public float getMix () {
return mix; return alpha;
} }
public void setMix (float mix) { public void setMix (float mix) {
this.mix = mix; this.alpha = mix;
} }
public float getTimeScale () { public float getTimeScale () {
@ -447,6 +480,14 @@ public class AnimationState {
this.eventThreshold = eventThreshold; this.eventThreshold = eventThreshold;
} }
public float getAttachmentThreshold () {
return attachmentThreshold;
}
public void setAttachmentThreshold (float attachmentThreshold) {
this.attachmentThreshold = attachmentThreshold;
}
public TrackEntry getNext () { public TrackEntry getNext () {
return next; return next;
} }