[as3] Ported holdPrevious in AnimationState. See #1169.

This commit is contained in:
badlogic 2018-09-10 16:16:25 +02:00
parent 4202fd1363
commit 018d3a9e3d
6 changed files with 87 additions and 75 deletions

View File

@ -38,8 +38,8 @@ package spine.animation {
public class AnimationState {
public static var SUBSEQUENT : int = 0;
public static var FIRST : int = 1;
public static var DIP : int = 2;
public static var DIP_MIX : int = 3;
public static var HOLD : int = 2;
public static var HOLD_MIX : int = 3;
internal static var emptyAnimation : Animation = new Animation("<empty>", new Vector.<Timeline>(), 0);
public var data : AnimationStateData;
public var tracks : Vector.<TrackEntry> = new Vector.<TrackEntry>();
@ -112,6 +112,7 @@ package spine.animation {
// End mixing from entries once all have completed.
var from : TrackEntry = current.mixingFrom;
current.mixingFrom = null;
if (from != null) from.mixingTo = null;
while (from != null) {
queue.end(from);
from = from.mixingFrom;
@ -138,6 +139,7 @@ package spine.animation {
// Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).
if (from.totalAlpha == 0 || to.mixDuration == 0) {
to.mixingFrom = from.mixingFrom;
if (from.mixingFrom != null) from.mixingFrom.mixingTo = to;
to.interruptAlpha = from.interruptAlpha;
queue.end(from);
}
@ -174,11 +176,11 @@ package spine.animation {
var timelineCount : int = current.animation.timelines.length;
var timelines : Vector.<Timeline> = current.animation.timelines;
var ii : int = 0;
if (mix == 1 || blend == MixBlend.add) {
if (i == 0 && (mix == 1 || blend == MixBlend.add)) {
for (ii = 0; ii < timelineCount; ii++)
Timeline(timelines[ii]).apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.In);
} else {
var timelineData : Vector.<int> = current.timelineData;
var timelineMode : Vector.<int> = current.timelineMode;
var firstFrame : Boolean = current.timelinesRotation.length == 0;
if (firstFrame) current.timelinesRotation.length = timelineCount << 1;
@ -186,7 +188,7 @@ package spine.animation {
for (ii = 0; ii < timelineCount; ii++) {
var timeline : Timeline = timelines[ii];
var timelineBlend : MixBlend = timelineData[ii] == AnimationState.SUBSEQUENT ? blend : MixBlend.setup;
var timelineBlend : MixBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : MixBlend.setup;
if (timeline is RotateTimeline) {
applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
} else
@ -222,15 +224,15 @@ package spine.animation {
var animationLast : Number = from.animationLast, animationTime : Number = from.getAnimationTime();
var timelineCount : int = from.animation.timelines.length;
var timelines : Vector.<Timeline> = from.animation.timelines;
var alphaDip : Number = from.alpha * to.interruptAlpha;
var alphaMix : Number = alphaDip * (1 - mix);
var alphaHold : Number = from.alpha * to.interruptAlpha;
var alphaMix : Number = alphaHold * (1 - mix);
var i : int = 0;
if (blend == MixBlend.add) {
for (i = 0; i < timelineCount; i++)
timelines[i].apply(skeleton, animationLast, animationTime, events, alphaMix, blend, MixDirection.Out);
} else {
var timelineData : Vector.<int> = from.timelineData;
var timelineDipMix : Vector.<TrackEntry> = from.timelineDipMix;
var timelineMode : Vector.<int> = from.timelineMode;
var timelineHoldMix : Vector.<TrackEntry> = from.timelineHoldMix;
var firstFrame : Boolean = from.timelinesRotation.length == 0;
if (firstFrame) from.timelinesRotation.length = timelineCount << 1;
@ -241,7 +243,7 @@ package spine.animation {
var timeline : Timeline = timelines[i];
var timelineBlend: MixBlend;
var alpha : Number = 0;
switch (timelineData[i]) {
switch (timelineMode[i]) {
case SUBSEQUENT:
if (!attachments && timeline is AttachmentTimeline) continue;
if (!drawOrder && timeline is DrawOrderTimeline) continue;
@ -252,14 +254,14 @@ package spine.animation {
timelineBlend = MixBlend.setup;
alpha = alphaMix;
break;
case DIP:
case HOLD:
timelineBlend = MixBlend.setup;
alpha = alphaDip;
alpha = alphaHold;
break;
default:
timelineBlend = MixBlend.setup;
var dipMix : TrackEntry = timelineDipMix[i];
alpha = alphaDip * Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
var holdMix : TrackEntry = timelineHoldMix[i];
alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration);
break;
}
from.totalAlpha += alpha;
@ -399,6 +401,7 @@ package spine.animation {
if (from == null) break;
queue.end(from);
entry.mixingFrom = null;
entry.mixingTo = null;
entry = from;
}
@ -414,6 +417,7 @@ package spine.animation {
if (from != null) {
if (interrupt) queue.interrupt(from);
current.mixingFrom = from;
from.mixingTo = current;
current.mixTime = 0;
// Store the interrupted mix percentage.
@ -529,6 +533,7 @@ package spine.animation {
entry.trackIndex = trackIndex;
entry.animation = animation;
entry.loop = loop;
entry.holdPrevious = false;
entry.eventThreshold = 0;
entry.attachmentThreshold = 0;
@ -565,14 +570,69 @@ package spine.animation {
private function _animationsChanged() : void {
animationsChanged = false;
var propertyIDs : Dictionary = this.propertyIDs = new Dictionary();
var mixingTo : Vector.<TrackEntry> = this.mixingTo;
propertyIDs = new Dictionary();
for (var i : int = 0, n : int = tracks.length; i < n; i++) {
var entry : TrackEntry = tracks[i];
if (entry != null && (i == 0 || entry.mixBlend != MixBlend.add))
entry.setTimelineData(null, mixingTo, propertyIDs);
if (entry == null) continue;
while (entry.mixingFrom != null)
entry = entry.mixingFrom;
do {
if (entry.mixingTo == null || entry.mixBlend != MixBlend.add) setTimelineModes(entry);
entry = entry.mixingTo;
} while (entry != null);
}
}
private function setTimelineModes (entry: TrackEntry) {
var to: TrackEntry = entry.mixingTo;
var timelines : Vector.<Timeline> = entry.animation.timelines;
var timelinesCount : int = entry.animation.timelines.length;
var timelineMode : Vector.<int> = entry.timelineMode;
timelineMode.length = timelinesCount;
var timelineHoldMix : Vector.<TrackEntry> = entry.timelineHoldMix;
timelineHoldMix.length = 0;
var propertyIDs: Dictionary = this.propertyIDs;
if (to != null && to.holdPrevious) {
for (var i : int = 0; i < timelinesCount; i++) {
propertyIDs[timelines[i].getPropertyId().toString()] = true;
timelineMode[i] = HOLD;
}
return;
}
outer:
for (var i : int = 0; i < timelinesCount; i++) {
var intId : int = timelines[i].getPropertyId();
var id : String = intId.toString();
var contained: Object = propertyIDs[id];
propertyIDs[id] = true;
if (contained != null) {
timelineMode[i] = AnimationState.SUBSEQUENT;
} else if (to == null || !hasTimeline(to, intId)) {
timelineMode[i] = AnimationState.FIRST;
} else {
for (var next : TrackEntry = to.mixingTo; next != null; next = next.mixingTo) {
if (hasTimeline(next, intId)) continue;
if (entry.mixDuration > 0) {
timelineMode[i] = AnimationState.HOLD_MIX;
timelineHoldMix[i] = entry;
continue outer;
}
break;
}
timelineMode[i] = AnimationState.HOLD;
}
}
}
private static function hasTimeline (entry: TrackEntry, id : int) : Boolean {
var timelines : Vector.<Timeline> = entry.animation.timelines;
for (var i : int = 0, n : int = entry.animation.timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id) return true;
return false;
}
public function getCurrent(trackIndex : int) : TrackEntry {
if (trackIndex >= tracks.length) return null;

View File

@ -34,7 +34,7 @@ package spine.animation {
public class TrackEntry implements Poolable {
public var animation : Animation;
public var next : TrackEntry, mixingFrom : TrackEntry;
public var next : TrackEntry, mixingFrom : TrackEntry, mixingTo: TrackEntry;
public var onStart : Listeners = new Listeners();
public var onInterrupt : Listeners = new Listeners();
public var onEnd : Listeners = new Listeners();
@ -42,14 +42,14 @@ package spine.animation {
public var onComplete : Listeners = new Listeners();
public var onEvent : Listeners = new Listeners();
public var trackIndex : int;
public var loop : Boolean;
public var loop : Boolean, holdPrevious: Boolean;
public var eventThreshold : Number, attachmentThreshold : Number, drawOrderThreshold : Number;
public var animationStart : Number, animationEnd : Number, animationLast : Number, nextAnimationLast : Number;
public var delay : Number, trackTime : Number, trackLast : Number, nextTrackLast : Number, trackEnd : Number, timeScale : Number;
public var alpha : Number, mixTime : Number, mixDuration : Number, interruptAlpha : Number, totalAlpha : Number = 0;
public var mixBlend: MixBlend = MixBlend.replace;
public var timelineData : Vector.<int> = new Vector.<int>();
public var timelineDipMix : Vector.<TrackEntry> = new Vector.<TrackEntry>();
public var timelineMode : Vector.<int> = new Vector.<int>();
public var timelineHoldMix : Vector.<TrackEntry> = new Vector.<TrackEntry>();
public var timelinesRotation : Vector.<Number> = new Vector.<Number>();
public function TrackEntry() {
@ -67,6 +67,7 @@ package spine.animation {
public function reset() : void {
next = null;
mixingFrom = null;
mixingTo = null;
animation = null;
onStart.listeners.length = 0;
onInterrupt.listeners.length = 0;
@ -74,60 +75,10 @@ package spine.animation {
onDispose.listeners.length = 0;
onComplete.listeners.length = 0;
onEvent.listeners.length = 0;
timelineData.length = 0;
timelineDipMix.length = 0;
timelineMode.length = 0;
timelineHoldMix.length = 0;
timelinesRotation.length = 0;
}
public function setTimelineData (to: TrackEntry, mixingToArray : Vector.<TrackEntry>, propertyIDs : Dictionary) : TrackEntry {
if (to != null) mixingToArray.push(to);
var lastEntry : TrackEntry = mixingFrom != null ? mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null) mixingToArray.pop();
var mixingTo : Vector.<TrackEntry> = mixingToArray;
var mixingToLast : int = mixingToArray.length - 1;
var timelines : Vector.<Timeline> = animation.timelines;
var timelinesCount : int = animation.timelines.length;
var timelineData : Vector.<int> = this.timelineData;
timelineData.length = timelinesCount;
this.timelineDipMix.length = 0;
var timelineDipMix : Vector.<TrackEntry> = this.timelineDipMix;
timelineDipMix.length = timelinesCount;
outer:
for (var i : int = 0; i < timelinesCount; i++) {
var intId : int = timelines[i].getPropertyId();
var id : String = intId.toString();
var contained: Object = propertyIDs[id];
propertyIDs[id] = true;
if (contained != null) {
timelineData[i] = AnimationState.SUBSEQUENT;
} else if (to == null || !to.hasTimeline(intId)) {
timelineData[i] = AnimationState.FIRST;
} else {
for (var ii : int = mixingToLast; ii >= 0; ii--) {
var entry : TrackEntry = mixingTo[ii];
if (!entry.hasTimeline(intId)) {
if (entry.mixDuration > 0) {
timelineData[i] = AnimationState.DIP_MIX;
timelineDipMix[i] = entry;
continue outer;
}
break;
}
}
timelineData[i] = AnimationState.DIP;
}
}
return lastEntry;
}
private function hasTimeline (id : int) : Boolean {
var timelines : Vector.<Timeline> = animation.timelines;
for (var i : int = 0, n : int = animation.timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id) return true;
return false;
}
}
public function resetRotationDirection() : void {
timelinesRotation.length = 0;

View File

@ -69,6 +69,7 @@ package spine.examples {
var skeletonData : SkeletonData = json.readSkeletonData(new SpineboyJson());
var stateData : AnimationStateData = new AnimationStateData(skeletonData);
stateData.setMixByName("walk", "run", 0.4);
stateData.setMixByName("run", "jump", 0.4);
stateData.setMixByName("jump", "run", 0.4);
stateData.setMixByName("jump", "jump", 0.4);