应用动画
Spine提供了两个应用动画API。
AnimationState API
AnimationState支持随时应用动画、排队稍后播放、混合动画(交叉淡入淡出)及在各动画上应用多个动画(分层)。
AnimationState是有状态的,用于存储动画时间及应用动画的其他参数。虽然一个AnimationState可以调整多个骨架姿势,但是很少有情况需要让多个骨架姿势完全一样。通常每个骨架实例使用一个AnimationState实例。
AnimationState建立在时间轴API上,可处理多数播放需求,向后播放除外。如需反向播放,可直接使用时间轴API,或使用框选缩放来复制和反向播放动画。
AnimationState update
方法用于获取自上次调用后已过时间和更新内部状态。apply
方法用于获取一个骨架并应用相应动画。
...
// 每一帧:
state.update(delta);
state.apply(skeleton);
混合时间
创建一个AnimationState实例需要提供一个AnimationStateData。当AnimationState更改当前动画时,会使用AnimationStateData中定义的混合时间自动混合动画(交叉淡入淡出),从而实现流畅的动画过渡。
stateData.setDefaultMix(0.1);
stateData.setMix("walk", "jump", 0.2);
stateData.setMix("jump", "walk", 0.4);
stateData.setMix("jump", "run", 0.25);
stateData.setMix("walk", "shoot", 0);
AnimationState state = new AnimationState(stateData);
无需为每个动画手动指定混合时间,设置一个默认混合时间即可。还可使用TrackEntry mixDuration属性逐例设置混合时间:
entry.mixDuration = 0.6;
如"Data"后缀所示,AnimationStateData是无状态的。同一个AnimationStateData实例可与多个AnimationStates共用。
通道(Track)
Track可分层应用动画,每个track存储了一个动画和播放参数。Track编号从零累加(track索引在内部是一个数组索引)。在将AnimationState应用到一个骨架后,track动画会从最低的track号开始依序应用。
Track有许多用途,例如,没有任何关键帧的动画可在高层track中运行,只覆盖有关键帧的低层track。例如,Track 0可以有行走、奔跑、游泳或其他动画,track 1可以有一个只为手臂和开枪设置了关键帧的射击动画。此外,为高层track设置TrackEntry alpha可使其与下面的轨道混合。例如,track 0可以有一个行走动画,track 1可以有一个跛行动画。当玩家受伤时,track 1的alpha值会增加,跛行会加重。
播放
设置track动画通过调用setAnimation完成。将使用指定的动画取代该track中的当前动画和任何已排队的动画。如果在前一动画和当前动画之间定义了混合动画时间,则当前动画将在混合动画时间上混出,让动画过渡更流畅。
setAnimation
返回一个TrackEntry,可以多种方式自定义播放。
默认动画将继续应用直至另一动画播放或track清空。要在一个具体时间后停止动画,可设置TrackEntry trackEnd时间。
排队
要排队动画在将来播放,可调用addAnimation,安排该动画在此track当前动画或最后排队的动画后播放。如果此track空了,则等于调用setAnimation
。
addAnimation
返回一个TrackEntry,可用于自定义播放。
空动画
当在空track上设置一个动画,则立即开始播放。类似地,如果清空了一个track,动画将停止应用。要混入或混出一个动画,可指定一个空动画,即没有时间轴的动画。空动画作为一个占位符,可设置混合时间。为了方便,提供有setEmptyAnimation和addEmptyAnimation方法用于设置或排队空动画。
要从装配姿势混入一个动画,可设置一个空动画,然后设置混合时间:
TrackEntry entry = state.addAnimation(track, "run", true, 0);
entry.mixDuration = 1.5;
要混出一个动画到装配姿势,可设置或排队一个指定了混合时间的空动画:
state.addEmptyAnimation(track, 1.5, 0);
当动画到达TrackEntry trackEnd时间时,该动画设置的关键帧属性将设置装配姿势,并清空track。可根据需要使用setEmptyAnimation
或addEmptyAnimation
将骨架混回到装配姿势,而非让其即刻发生。
TrackEntry
设置或排队动画的方法返回一个TrackEntry,可用于进一步自定义播放。参考TrackEntry API参考获取许多可用设置。
引用
可保留一个TrackEntry引用,例如可随时调整alpha
或timeScale
属性。但是必须注意不要在dispose
侦听器事件发生后保留该引用。
侦听器
应用程序可注册一个回调以通知TrackEntry生命周期事件。AnimationState上的addListener
可为所有TrackEntry事件注册侦听器。也可以在一个具体TrackEntry上设置侦听器以只接收该entry的事件。
AnimationStateListener上列出了可能的事件并保证按指定的顺序发生。事件在AnimationState update
或apply
方法完成内部处理时排队,之后在方法刚返回前通知侦听器。这样侦听器可以安全地操纵AnimationState,比如设置动画或清空tracks。但是仍会触发所有已排队的事件,除非使用clearListenerNotifications。
侦听器中的AnimationState更改(如设置一个新动画)不会应用到骨架直至下次调用AnimationState apply
时。这可在侦听器中完成,但是必须注意先调用update
:
state.setAnimation(0, "jump", false);
state.update(0); // 更新内部状态。
state.apply(skeleton);
apply
方法不会更改任何内部状态,使一个AnimationState可应用到多个骨架。调用update
让AnimationState知道所有应用完成了,后续的apply
调用是下一帧的。如果未调用update
,apply
可能触发同一个侦听器,导致无限循环和堆栈溢出。
时间轴API
时间轴API是应用动画最低层的API,包含Animation和Timeline类。这些类都是无状态的,必须在外部存储和操纵应用动画的时间及其他参数。此API对动画播放提供大部分控制,但是自己需要更多工作来管理播放状态。所以多数用户偏好使用AnimationState API。
一个动画非常简单,有一个名称和一系列时间轴。每个时间轴知道在何时如何修改一个具体骨架属性。将动画应用到骨架是通过为动画中的每个时间轴调用apply完成。
alpha = 1; // For mixing between the current or setup pose (0) or the animation pose (1).
blend = MixBlend.first; // How the current or setup pose is mixed with the animation pose.
direction = MixDirection.in; // Whether mixing out to the setup pose or in to the animation pose.
for (Timeline timeline : animation.timelines)
timeline.apply(skeleton, lastTime, time, events, alpha, blend, direction);
// The events list contains any events fired between lastTime and time.
// Process them here, then clear the list.
events.clear();
lastTime = time;
动画有一个很方便的apply
方法,只需为每个时间轴调用 apply
即可。
animation.apply(skeleton, lastTime, time, loop, events, alpha, blend, direction);