- تم التحرير
unity timeline custom spine track test
Multi Track Blending(Support Preview),
Clip Blending,
Start Time Offset(Clip In),
Speed Multiplier,
Select AnimationName from drop down,
Reverse
Looks great, congrats !
Do you plan to share by any chance ?
This looks very nice!
Which version of Unity did you implement this for?
Would you be interested in contributing your code to Spine?
Harald wroteThis looks very nice!
Which version of Unity did you implement this for?
Would you be interested in contributing your code to Spine?
Unity 2018.3.
This is experimental code. I need more test.
It has some issues and not optimized yet.
public class CustomSpineAnimationMixerBehaviour : PlayableBehaviour
{
private const float FIRST_CLIP_BLEND_DURATION = 0.2f;
private const float FINAL_CLIP_BLEND_DURATION = 0.2f;
private SkeletonAnimation _trackBindingSkeletonAnimation;
private Skeleton _trackBindingSkeleton;
private TrackEntry _oldTrack;
private bool _firstFrameHappend;
public override void PrepareFrame(Playable playable, FrameData info)
{
if (_trackBindingSkeletonAnimation == null) return;
if (_trackBindingSkeleton == null) _trackBindingSkeleton = _trackBindingSkeletonAnimation.Skeleton;
int inputCount = playable.GetInputCount();
for (int i = 0; i < inputCount; i++)
{
ScriptPlayable<CustomSpineAnimationBehaviour> inputPlayable = (ScriptPlayable<CustomSpineAnimationBehaviour>)playable.GetInput(i);
CustomSpineAnimationBehaviour clipBehaviourData = inputPlayable.GetBehaviour();
clipBehaviourData.Init(_trackBindingSkeleton.Data);
if (clipBehaviourData.animation == null) continue;
//set key
clipBehaviourData.animation.SetKeyedItemsToSetupPose(_trackBindingSkeleton);
}
}
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
_trackBindingSkeletonAnimation = playerData as SkeletonAnimation;
if (_trackBindingSkeletonAnimation == null) return;
if (_trackBindingSkeleton == null) _trackBindingSkeleton = _trackBindingSkeletonAnimation.Skeleton;
if (_firstFrameHappend == false)
{
_oldTrack = _trackBindingSkeletonAnimation.AnimationState?.GetCurrent(0);
_firstFrameHappend = true;
}
if (_oldTrack != null)
{
var playableTime = (float)playable.GetTime();
var playableDuration = (float)playable.GetGraph().GetRootPlayable(0).GetDuration();
var firstClipBlend = Mathf.Max(0, 1 - playableTime / FIRST_CLIP_BLEND_DURATION);
var finalClipBlend = Mathf.Max(0, 1 - (playableDuration - playableTime) / FINAL_CLIP_BLEND_DURATION);
_oldTrack.Alpha = firstClipBlend + finalClipBlend;
}
int inputCount = playable.GetInputCount();
int currentInputs = 0;
for (int i = 0; i < inputCount; i++)
{
//check weight
float inputWeight = playable.GetInputWeight(i);
if (Mathf.Approximately(inputWeight, 0f)) continue;
//check animation
ScriptPlayable<CustomSpineAnimationBehaviour> inputPlayable = (ScriptPlayable<CustomSpineAnimationBehaviour>)playable.GetInput(i);
CustomSpineAnimationBehaviour clipBehaviourData = inputPlayable.GetBehaviour();
clipBehaviourData.Init(_trackBindingSkeleton.Data);
if (clipBehaviourData.animation == null) continue;
//set animation
float time = clipBehaviourData.reverse ? (float)(inputPlayable.GetDuration() - inputPlayable.GetTime()) : (float)inputPlayable.GetTime();
MixBlend mixBlend = currentInputs == 0 ? MixBlend.Setup : MixBlend.First;
MixDirection mixDirection = inputWeight < 1 && currentInputs > 1 ? MixDirection.Out : MixDirection.In;
clipBehaviourData.animation.Apply(_trackBindingSkeleton, 0f, time, clipBehaviourData.loop, null, inputWeight, mixBlend, mixDirection);
currentInputs++;
}
_trackBindingSkeletonAnimation.Update(0);
_trackBindingSkeletonAnimation.LateUpdate();
}
public override void OnPlayableDestroy(Playable playable)
{
if (_trackBindingSkeleton != null) _trackBindingSkeleton.SetToSetupPose();
if (_trackBindingSkeletonAnimation != null) _trackBindingSkeletonAnimation.Update(0);
}
}
This is part of mixbehaviour class.
Is it possible to contribute my code?
(Sorry for my bad English grammer...)
bali33 wroteLooks great, congrats !
Do you plan to share by any chance ?
I hope so
Thanks very much for sharing the code here!
Since you wrote it for 2018, I fear we will have to come up with something different for Unity 2019 (since the API seems to have changed in this regard, I didn't get to have a more in-depth look at it yet), but still - thanks for the input! I will very soon get to updating the whole timeline features to Unity 2019, so every input is welcome!