mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Minor AnimationState fixes.
- Added mixAlpha to keep it separate from alpha. - Stored mixAlpha on the "mixing to" entry (where mixTime, etc is stored), not the mixingFrom entry. - Fixed weirdness using TrackEntry alpha. - Removed clearing timelinesRotation to avoid rotations flipping to other side when a new animation is set. - Added TrackEntry#resetRotationDirections to give control over rotations when using alpha over long periods of time.
This commit is contained in:
parent
7ac77fb177
commit
fae60d8899
@ -163,7 +163,7 @@ public class AnimationState {
|
|||||||
|
|
||||||
// Apply mixing from entries first.
|
// Apply mixing from entries first.
|
||||||
float mix = current.alpha;
|
float mix = current.alpha;
|
||||||
if (current.mixingFrom != null) mix = applyMixingFrom(current, skeleton, mix);
|
if (current.mixingFrom != null) mix *= applyMixingFrom(current, skeleton);
|
||||||
|
|
||||||
// Apply current entry.
|
// Apply current entry.
|
||||||
float animationLast = current.animationLast, animationTime = current.getAnimationTime();
|
float animationLast = current.animationLast, animationTime = current.getAnimationTime();
|
||||||
@ -195,9 +195,9 @@ public class AnimationState {
|
|||||||
queue.drain();
|
queue.drain();
|
||||||
}
|
}
|
||||||
|
|
||||||
private float applyMixingFrom (TrackEntry entry, Skeleton skeleton, float alpha) {
|
private float applyMixingFrom (TrackEntry entry, Skeleton skeleton) {
|
||||||
TrackEntry from = entry.mixingFrom;
|
TrackEntry from = entry.mixingFrom;
|
||||||
if (from.mixingFrom != null) applyMixingFrom(from, skeleton, alpha);
|
if (from.mixingFrom != null) applyMixingFrom(from, skeleton);
|
||||||
|
|
||||||
float mix;
|
float mix;
|
||||||
if (entry.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
if (entry.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
||||||
@ -205,16 +205,15 @@ public class AnimationState {
|
|||||||
else {
|
else {
|
||||||
mix = entry.mixTime / entry.mixDuration;
|
mix = entry.mixTime / entry.mixDuration;
|
||||||
if (mix > 1) mix = 1;
|
if (mix > 1) mix = 1;
|
||||||
mix *= alpha;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Array<Event> events = mix < from.eventThreshold ? this.events : null;
|
Array<Event> events = mix < from.eventThreshold ? this.events : null;
|
||||||
boolean attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold;
|
boolean attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold;
|
||||||
float animationLast = from.animationLast, animationTime = from.getAnimationTime();
|
float animationLast = from.animationLast, animationTime = from.getAnimationTime();
|
||||||
alpha = from.alpha * (1 - mix);
|
|
||||||
int timelineCount = from.animation.timelines.size;
|
int timelineCount = from.animation.timelines.size;
|
||||||
Object[] timelines = from.animation.timelines.items;
|
Object[] timelines = from.animation.timelines.items;
|
||||||
boolean[] timelinesFirst = from.timelinesFirst.items;
|
boolean[] timelinesFirst = from.timelinesFirst.items;
|
||||||
|
float alpha = from.alpha * entry.mixAlpha * (1 - mix);
|
||||||
|
|
||||||
boolean firstFrame = from.timelinesRotation.size == 0;
|
boolean firstFrame = from.timelinesRotation.size == 0;
|
||||||
if (firstFrame) from.timelinesRotation.setSize(timelineCount << 1);
|
if (firstFrame) from.timelinesRotation.setSize(timelineCount << 1);
|
||||||
@ -385,10 +384,8 @@ public class AnimationState {
|
|||||||
current.mixingFrom = from;
|
current.mixingFrom = from;
|
||||||
current.mixTime = 0;
|
current.mixTime = 0;
|
||||||
|
|
||||||
from.timelinesRotation.clear();
|
// If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero.
|
||||||
|
if (from.mixingFrom != null) current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
||||||
// If not completely mixed in, set alpha so mixing out happens from current mix to zero.
|
|
||||||
if (from.mixingFrom != null) from.alpha *= Math.min(from.mixTime / from.mixDuration, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.start(current);
|
queue.start(current);
|
||||||
@ -544,6 +541,7 @@ public class AnimationState {
|
|||||||
entry.timeScale = 1;
|
entry.timeScale = 1;
|
||||||
|
|
||||||
entry.alpha = 1;
|
entry.alpha = 1;
|
||||||
|
entry.mixAlpha = 1;
|
||||||
entry.mixTime = 0;
|
entry.mixTime = 0;
|
||||||
entry.mixDuration = last == null ? 0 : data.getMix(last.animation, animation);
|
entry.mixDuration = last == null ? 0 : data.getMix(last.animation, animation);
|
||||||
return entry;
|
return entry;
|
||||||
@ -563,7 +561,7 @@ public class AnimationState {
|
|||||||
|
|
||||||
IntSet propertyIDs = this.propertyIDs;
|
IntSet propertyIDs = this.propertyIDs;
|
||||||
|
|
||||||
// Compute timelinesFirst from lowest to highest track entries.
|
// Set timelinesFirst for all entries, from lowest track to highest.
|
||||||
int i = 0, n = tracks.size;
|
int i = 0, n = tracks.size;
|
||||||
propertyIDs.clear();
|
propertyIDs.clear();
|
||||||
for (; i < n; i++) { // Find first non-null entry.
|
for (; i < n; i++) { // Find first non-null entry.
|
||||||
@ -587,11 +585,11 @@ public class AnimationState {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IntSet propertyIDs = this.propertyIDs;
|
IntSet propertyIDs = this.propertyIDs;
|
||||||
Array<Timeline> timelines = entry.animation.timelines;
|
int n = entry.animation.timelines.size;
|
||||||
int n = timelines.size;
|
Object[] timelines = entry.animation.timelines.items;
|
||||||
boolean[] usage = entry.timelinesFirst.setSize(n);
|
boolean[] usage = entry.timelinesFirst.setSize(n);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
propertyIDs.add(timelines.get(i).getPropertyId());
|
propertyIDs.add(((Timeline)timelines[i]).getPropertyId());
|
||||||
usage[i] = true;
|
usage[i] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -604,11 +602,11 @@ public class AnimationState {
|
|||||||
|
|
||||||
private void checkTimelinesUsage (TrackEntry entry, BooleanArray usageArray) {
|
private void checkTimelinesUsage (TrackEntry entry, BooleanArray usageArray) {
|
||||||
IntSet propertyIDs = this.propertyIDs;
|
IntSet propertyIDs = this.propertyIDs;
|
||||||
Array<Timeline> timelines = entry.animation.timelines;
|
int n = entry.animation.timelines.size;
|
||||||
int n = timelines.size;
|
Object[] timelines = entry.animation.timelines.items;
|
||||||
boolean[] usage = usageArray.setSize(n);
|
boolean[] usage = usageArray.setSize(n);
|
||||||
for (int i = 0; i < n; i++)
|
for (int i = 0; i < n; i++)
|
||||||
usage[i] = propertyIDs.add(timelines.get(i).getPropertyId());
|
usage[i] = propertyIDs.add(((Timeline)timelines[i]).getPropertyId());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */
|
/** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */
|
||||||
@ -924,6 +922,17 @@ public class AnimationState {
|
|||||||
return mixingFrom;
|
return mixingFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resets the rotation directions for mixing this entry's rotate timelines. This can be useful to avoid bones rotating the
|
||||||
|
* long way around when using {@link #alpha} and starting animations on other tracks.
|
||||||
|
* <p>
|
||||||
|
* Mixing involves finding a rotation between two others, which has two possible solutions: the short way or the long way
|
||||||
|
* around. The two rotations likely change over time, so which direction is the short or long way also changes. If the short
|
||||||
|
* way was always chosen, bones would flip to the other side when that direction became the long way. TrackEntry chooses the
|
||||||
|
* short way the first time it is applied and remembers that direction. */
|
||||||
|
public void resetRotationDirections () {
|
||||||
|
timelinesRotation.clear();
|
||||||
|
}
|
||||||
|
|
||||||
public String toString () {
|
public String toString () {
|
||||||
return animation == null ? "<none>" : animation.name;
|
return animation == null ? "<none>" : animation.name;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user