描述动画
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);
然后,你可以使用以下任意一种方式播放它:
- 对生成的动画机调用 Play 函数,将其插入到动画工作列表,下一帧开始播放:
(1f + 0.5f / ball.MQuad(x => x.position, Vector3.zero, Vector3.one)).Play();
- 如果你有特殊的需要,需要在播放后立刻对相关属性产生修改,则可以:
(1f + 0.5f / ball.MQuad(x => x.position, Vector3.zero, Vector3.one)).PlayImmidiate();
- 如果你觉得上面的写法堆在一行里面太冗长,也可以:
MAni.Make(
1f + 0.5f / ball.MQuad(x => x.position, Vector3.zero, Vector3.one)
).Play();
嵌套动画
每个描述语句都会返回一个 MilInstantAnimator
,通过其提供的流式接口,可以将动画进行组合嵌套。
例如,我们需要实现这样一种动画:
- 球从透明逐渐变为白色
- 球变色的同时,音乐音量逐渐从0过渡到1
- 上述操作都完成后,使球移动
- 在球移动中途,使其变大
- 上述操作都完成后,依次做这样的动作:相机的
fov
减小、相机旋转
那么,就可以如以下方式嵌套:
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()
构造的动画机可以不断复用。