跳到主要内容

一般动画机

本章节介绍的动画方法,都是基于 MilInstantAnimator,也就是一般动画机。

本小节将展开介绍一般动画机的其他机制,下文出现的方法除标注”*“外均基于流式接口设计,即方法本身的返回值也是一个 MilInstantAnimator

例如,我们在前面小节提到的 ThenThenOneByOneAnd 都属于流式接口,也就是说,你可以对 MilInstantAnimator 进行任意的如下所示的方法调用嵌套:

MAni.Make(
...
).MethodA(...)
.MethodB(...)
.MethodC(
...
).Play();

生命周期

默认情况下,一般动画机会在当前场景被卸载时自动停止播放,避免一些仍未播放结束的动画操作已被卸载的物体。

若你希望动画机不会在场景被卸载时自动停止,例如你正在对 DontDestroyOnLoad 的物体执行动画操作,则可调用方法:

DontStopOnLoad()

播放相关

令动画机循环播放:

EnableLooping()

暂停动画机*:

Pause()

停止动画机*:

Stop()

停止动画机,并复原动画机的改动*:

Reset()

时间源

默认情况下,一般动画机将使用 UnscaledTime 更新动画,这意味着,它不会受到 Time.timeScale 的影响。

如果你希望动画受其影响,可调用:

SetTimeSource(TimeSource.ScaledTime);

重置模式

一般动画机会在动画从头开始播放时自动调用一次 Reset(),而”复原动画机的改动“的程度取决于”重置模式“。

重置模式分为以下两种:

  • ResetToOriginalState(默认)

    该模式会将 动画机操作的对象的相关属性 还原至 开始播放时刻记录的属性状态

  • ResetToInitialState

    该模式会将 动画机操作的对象的相关属性 还原至 动画机在0s时刻时所有动画描述的属性的状态

可以使用该方法设置重置模式:

UsingResetMode(AnimationResetMode.ResetToInitialState);
注意
  • 无开始值的动画始终使用 ResetToOriginalState 模式重置,无视 ResetToInitialState 的设定。
  • 混合模式为 Additive 的动画始终使用 ResetToOriginalState 模式重置,无视 ResetToInitialState 的设定。
  • 由于 Play() 方法是将动画机的动画任务提交,下一帧才会开始播放,有时可能会出现一种情况:你把 Canvas 显示出来了,但是动画下一帧开始播放,用户在那一帧突然看见了界面的骨架状态。为了规避这种情况,有两种解决办法:
    1. 使用 PlayImmidiate() 方法播放,使其在当前帧就应用动画状态。
    2. 使用 ResetToInitialState 的重置模式,动画虽然在下一帧才开始播放,但是 重置操作 是在当前帧完成的,设定此重置模式可以立刻将其变化至 动画 0s 时刻的状态,避免穿帮。

无开始值的动画机的复用

看完重置模式的介绍,你可能就会发现,如果你复用一个包含无开始值的动画的动画机,它会将对象状态还原至动画记录前的状态,这显然不是我们想要的。

此时,对于这种需求,我们在调用 Play 函数播放时,要显式地传入 revertToChanges 参数为 false,使其不重置 无开始值 的动画做的修改:

Play(null, false);

延后上一组动画

动画描述相关的方法,除了 ThenThenOneByOneAnd,还有最后的 Delayed

它会将紧邻的上一组动画整体延后播放指定秒数,例如:

MAni.Make(
1f / ballSpriteRender.MQuad(x => x.color, Color.clear, Color.white),
1f / music.MQuad(x => x.volume, 0f, 1f)
).Then(
2f / ballTransform.MQuad(x => x.position, Vector3.zero, Vector3.one * 3f),
1f + 0.5f / ballTransform.MQuad(x => x.localScale, Vector3.one, Vector3.one * 2f)
).Delayed(1f)
.ThenOneByOne(
1f / camera.MQuad(x => x.fieldOfView, 6f, 4.5f),
1f / camera.MQuad(x => x.localEulerAngles, Vector3.zero, new Vector3(0, 0, 20f))
).Play();

等价于:

MAni.Make(
1f / ballSpriteRender.MQuad(x => x.color, Color.clear, Color.white),
1f / music.MQuad(x => x.volume, 0f, 1f)
).Then(
// 注意这一组动画的 offset 变化
1f + 2f / ballTransform.MQuad(x => x.position, Vector3.zero, Vector3.one * 3f),
2f + 0.5f / ballTransform.MQuad(x => x.localScale, Vector3.one, Vector3.one * 2f)
).ThenOneByOne(
1f / camera.MQuad(x => x.fieldOfView, 6f, 4.5f),
1f / camera.MQuad(x => x.localEulerAngles, Vector3.zero, new Vector3(0, 0, 20f))
).Play();