跳到主要内容

描述动画

Milease 提供了一系列的 object 的扩展函数,函数名形式如:M<缓动函数名><缓动类型名>

例如,我们举例较常用的 Quad 缓动函数,并采用 Out 的缓动类型,那么这个函数名就叫 MQuadOut

特别地,当它的缓动类型是 In 时,则函数名只体现缓动函数名,即 MQuad

有关缓动函数和缓动类型的介绍,可参阅其他文章。

对任何成员构造动画机

[offset] + [duration] / object.MQuad(x => x.member, startValue, endValue) - [blendingMode];

以上就是一条描述动画的基本语句,其中 offset(延迟时间)、 duration(持续时间)、blendingMode(混合模式)是可选的。

举一个最简单的例子,假如我们需要使得 AudioSource 的音量在0.5秒内从0过渡到1:

0.5f / MyAudioSource.MQuad(x => x.volume, 0f, 1f);

这段语句便描述了这个动画操作,这个函数的第一个参数是一个 MemberExpression,用于选择操作对象 MyAudioSource 的何种成员。

同样的,我们可以描述 1秒后,在0.5秒内使得物体 ball 从一个点移动到另一个点:

1f + 0.5f / ball.MQuad(x => x.position, Vector3.zero, Vector3.one);

然后,你可以使用以下任意一种方式播放它:

  1. 对生成的动画机调用 Play 函数,将其插入到动画工作列表,下一帧开始播放:
(1f + 0.5f / ball.MQuad(x => x.position, Vector3.zero, Vector3.one)).Play();
  1. 如果你有特殊的需要,需要在播放后立刻对相关属性产生修改,则可以:
(1f + 0.5f / ball.MQuad(x => x.position, Vector3.zero, Vector3.one)).PlayImmidiate();
  1. 如果你觉得上面的写法堆在一行里面太冗长,也可以:
MAni.Make(
1f + 0.5f / ball.MQuad(x => x.position, Vector3.zero, Vector3.one)
).Play();

嵌套动画

每个描述语句都会返回一个 MilInstantAnimator,通过其提供的流式接口,可以将动画进行组合嵌套。

例如,我们需要实现这样一种动画:

  • 球从透明逐渐变为白色
  • 球变色的同时,音乐音量逐渐从0过渡到1
  • 上述操作都完成后,使球移动
  • 在球移动中途,使其变大
  • 上述操作都完成后,依次做这样的动作:相机的 fov 减小、相机旋转

那么,就可以如以下方式嵌套:

example.cs
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)
).ThenOneByOne(
1f / camera.MQuad(x => x.fieldOfView, 6f, 4.5f),
1f / camera.MQuad(x => x.localEulerAngles, Vector3.zero, new Vector3(0, 0, 20f))
).Play();

其中 Then 方法表示 接下来 提供的一组动画将会 同时进行,但是需要等待前面的动画都执行结束;ThenOneByOne 方法表示接下来提供的一组动画将会 依次进行,但是需要等待前面的动画都执行结束。

当然,还有 And 方法没有出现在例子中,它表示 接下来提供的一组动画将会和上一组动画 同时进行

这有点符合自然语言的逻辑,例如:

The ball appeared and the music started, then the ball moved and got bigger, then the camera approached, then the camera rotated.

注意

MilInstantAnimator 是引用类型,这意味着你可以在后续再向这个动画机追加新的动画内容,但是不推荐这样做——正在播放的动画机被修改本身是一个未定义行为。同时,还可能给你带来更高的项目维护成本。

无需开始值的动画

到这里,你可能会产生一个疑问,如果要做小球从当前位置移动到指定位置的动画,上面的写法是否有些啰嗦?

于是,我们要介绍一个新的动画描述方法:

[offset] + [duration] / object.MQuad(x => x.member, targetValue.ToThis());

例如,现在的小球位置是随机的,但无论它在哪里,都将它移动至 (0,0,0) 处:

(0.5f / ball.MQuad(x => x.position, Vector3.zero.ToThis())).Play();

例如,现在的小球颜色是随机的,但无论它是什么颜色,都将它变为完全透明:

(0.5f / ball.MQuad(x => x.color, Color.clear.ToThis())).Play();
信息

虽然该方法看似与之等价:

(0.5f / ball.MQuad(x => x.position, ball.position, Vector3.zero)).Play();

但若使用上面这一个写法,该动画机将需要反复重新构造,而使用 ToThis() 构造的动画机可以不断复用。