mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-10 09:08:42 +08:00
[unity] Timeline clip end behaviour made more consistent and configurable, mixes out to empty animation by default. Partially reverted b4fd09b6. See #1933. Closes #1807.
This commit is contained in:
parent
b949e79ca5
commit
a775209577
@ -51,7 +51,8 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
|
||||
SerializedProperty mixDurationProp = property.FindPropertyRelative("mixDuration");
|
||||
SerializedProperty holdPreviousProp = property.FindPropertyRelative("holdPrevious");
|
||||
SerializedProperty dontPauseWithDirectorProp = property.FindPropertyRelative("dontPauseWithDirector");
|
||||
SerializedProperty dontPauseOnStopProp = property.FindPropertyRelative("dontPauseOnStop");
|
||||
SerializedProperty dontEndWithClip = property.FindPropertyRelative("dontEndWithClip");
|
||||
SerializedProperty endMixOutDuration = property.FindPropertyRelative("endMixOutDuration");
|
||||
SerializedProperty eventProp = property.FindPropertyRelative("eventThreshold");
|
||||
SerializedProperty attachmentProp = property.FindPropertyRelative("attachmentThreshold");
|
||||
SerializedProperty drawOrderProp = property.FindPropertyRelative("drawOrderThreshold");
|
||||
@ -78,11 +79,19 @@ public class SpineAnimationStateDrawer : PropertyDrawer {
|
||||
"If set to true, the animation will continue playing when the Director is paused."));
|
||||
|
||||
singleFieldRect.y += lineHeightWithSpacing;
|
||||
EditorGUI.PropertyField(singleFieldRect, dontEndWithClip,
|
||||
new GUIContent("Don't End with Clip",
|
||||
"Normally when empty space follows the clip on the timeline, the empty animation is set on the track. " +
|
||||
"Set this parameter to true to continue playing the clip's animation instead."));
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(dontPauseWithDirectorProp.boolValue == true)) {
|
||||
EditorGUI.PropertyField(singleFieldRect, dontPauseOnStopProp,
|
||||
new GUIContent("Don't Pause on Stop",
|
||||
"If 'Don't Pause with Director' is true but this parameter is false, the animation will continue playing when the Graph is stopped, e.g. when reaching the track end."));
|
||||
singleFieldRect.y += lineHeightWithSpacing;
|
||||
|
||||
using (new EditorGUI.DisabledGroupScope(dontEndWithClip.boolValue == true)) {
|
||||
EditorGUI.PropertyField(singleFieldRect, endMixOutDuration,
|
||||
new GUIContent("Clip End Mix Out Duration",
|
||||
"When 'Don't End with Clip' is false, and the clip is followed by blank space or stopped, " +
|
||||
"the empty animation is set with this MixDuration. When set to a negative value, " +
|
||||
"the clip is paused instead."));
|
||||
}
|
||||
|
||||
singleFieldRect.y += lineHeightWithSpacing * 0.5f;
|
||||
|
||||
@ -54,7 +54,9 @@ namespace Spine.Unity.Playables {
|
||||
public float mixDuration = 0.1f;
|
||||
public bool holdPrevious = false;
|
||||
public bool dontPauseWithDirector = false;
|
||||
public bool dontPauseOnStop = false;
|
||||
[UnityEngine.Serialization.FormerlySerializedAs("dontPauseOnStop")]
|
||||
public bool dontEndWithClip = false;
|
||||
public float endMixOutDuration = 0.1f;
|
||||
|
||||
[Range(0, 1f)]
|
||||
public float attachmentThreshold = 0.5f;
|
||||
|
||||
@ -38,15 +38,19 @@ namespace Spine.Unity.Playables {
|
||||
public class SpineAnimationStateMixerBehaviour : PlayableBehaviour {
|
||||
|
||||
float[] lastInputWeights;
|
||||
bool lastAnyTrackPlaying = false;
|
||||
public int trackIndex;
|
||||
|
||||
IAnimationStateComponent animationStateComponent;
|
||||
bool pauseWithDirector = true;
|
||||
bool pauseWithDirectorButNotOnStop = false;
|
||||
bool endAtClipEnd = true;
|
||||
float endMixOutDuration = 0.1f;
|
||||
bool isPaused = false;
|
||||
TrackEntry pausedTrackEntry;
|
||||
float previousTimeScale = 1;
|
||||
|
||||
TrackEntry timelineStartedTrackEntry;
|
||||
|
||||
public override void OnBehaviourPause (Playable playable, FrameData info) {
|
||||
if (pauseWithDirector) {
|
||||
if (!isPaused)
|
||||
@ -56,8 +60,10 @@ namespace Spine.Unity.Playables {
|
||||
}
|
||||
|
||||
public override void OnGraphStop (Playable playable) {
|
||||
if (isPaused && pauseWithDirectorButNotOnStop)
|
||||
HandleResume(playable); // this stop event occurs after pause, so resume again
|
||||
if (endAtClipEnd)
|
||||
HandleClipEnd();
|
||||
else if (isPaused) // stop event occurred after pause, so resume again
|
||||
HandleResume(playable);
|
||||
}
|
||||
|
||||
public override void OnBehaviourPlay (Playable playable, FrameData info) {
|
||||
@ -70,7 +76,7 @@ namespace Spine.Unity.Playables {
|
||||
if (animationStateComponent == null) return;
|
||||
|
||||
TrackEntry current = animationStateComponent.AnimationState.GetCurrent(trackIndex);
|
||||
if (current != null) {
|
||||
if (current != null && current == timelineStartedTrackEntry) {
|
||||
previousTimeScale = current.TimeScale;
|
||||
current.TimeScale = 0;
|
||||
pausedTrackEntry = current;
|
||||
@ -86,9 +92,22 @@ namespace Spine.Unity.Playables {
|
||||
}
|
||||
}
|
||||
|
||||
protected void HandleClipEnd () {
|
||||
var state = animationStateComponent.AnimationState;
|
||||
if (endAtClipEnd &&
|
||||
timelineStartedTrackEntry != null &&
|
||||
timelineStartedTrackEntry == state.GetCurrent(trackIndex)) {
|
||||
|
||||
if (endMixOutDuration >= 0)
|
||||
state.SetEmptyAnimation(trackIndex, endMixOutDuration);
|
||||
else // pause if endMixOutDuration < 0
|
||||
timelineStartedTrackEntry.TimeScale = 0;
|
||||
timelineStartedTrackEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties.
|
||||
public override void ProcessFrame (Playable playable, FrameData info, object playerData) {
|
||||
|
||||
var skeletonAnimation = playerData as SkeletonAnimation;
|
||||
var skeletonGraphic = playerData as SkeletonGraphic;
|
||||
animationStateComponent = playerData as IAnimationStateComponent;
|
||||
@ -116,12 +135,15 @@ namespace Spine.Unity.Playables {
|
||||
this.lastInputWeights[i] = default(float);
|
||||
}
|
||||
var lastInputWeights = this.lastInputWeights;
|
||||
bool anyTrackPlaying = false;
|
||||
|
||||
// Check all clips. If a clip that was weight 0 turned into weight 1, call SetAnimation.
|
||||
for (int i = 0; i < inputCount; i++) {
|
||||
float lastInputWeight = lastInputWeights[i];
|
||||
float inputWeight = playable.GetInputWeight(i);
|
||||
bool trackStarted = lastInputWeight == 0 && inputWeight > 0;
|
||||
if (inputWeight > 0)
|
||||
anyTrackPlaying = true;
|
||||
lastInputWeights[i] = inputWeight;
|
||||
|
||||
if (trackStarted) {
|
||||
@ -129,7 +151,8 @@ namespace Spine.Unity.Playables {
|
||||
SpineAnimationStateBehaviour clipData = inputPlayable.GetBehaviour();
|
||||
|
||||
pauseWithDirector = !clipData.dontPauseWithDirector;
|
||||
pauseWithDirectorButNotOnStop = pauseWithDirector && clipData.dontPauseOnStop;
|
||||
endAtClipEnd = !clipData.dontEndWithClip;
|
||||
endMixOutDuration = clipData.endMixOutDuration;
|
||||
|
||||
if (clipData.animationReference == null) {
|
||||
float mixDuration = clipData.customDuration ? clipData.mixDuration : state.Data.DefaultMix;
|
||||
@ -147,6 +170,8 @@ namespace Spine.Unity.Playables {
|
||||
|
||||
if (clipData.customDuration)
|
||||
trackEntry.MixDuration = clipData.mixDuration;
|
||||
|
||||
timelineStartedTrackEntry = trackEntry;
|
||||
}
|
||||
//else Debug.LogWarningFormat("Animation named '{0}' not found", clipData.animationName);
|
||||
}
|
||||
@ -162,6 +187,9 @@ namespace Spine.Unity.Playables {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastAnyTrackPlaying && !anyTrackPlaying)
|
||||
HandleClipEnd();
|
||||
this.lastAnyTrackPlaying = anyTrackPlaying;
|
||||
}
|
||||
|
||||
#if SPINE_EDITMODEPOSE
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user