Animator倒放
撰写于 2019-07-03 修改于 2019-07-03 分类 Unity
Animator倒放
最近需要做一个技能编辑器,需要定位玩家的动作,在动作的某一帧,加入事件帧,用来触发特效。需要可以像在Animation编辑器中一样可以动态拖动时间条来定位某一帧,这就需要动作可以播放、暂停、倒放。但是玩家的动作是在Animator中播放的,处理起来有些复杂。以下是做的几种失败尝试。
通过speed实现倒放(错误1)
第一时间,想到的就是通过speed实现倒放,speed有两种:
- Animator.speed
- AnimatorStateInfo.speed
- AnimatorState.speed
Animator.speed: 通过尝试,发现speed=1
正常速度播放,speed<=0
停止播放,并不能回放,所以这种方法不行!
AnimatorStateInfo.speed: 也就是通过Animator.GetCurrentAnimatorStateInfo
方法获取到AnimatorStateInfo
,然后设置AnimatorStateInfo.speed
。是不是觉得一切顺利?!但是!AnimatorStateInfo.speed
是只读!readonly!,所以这种方法不行!
AnimatorState.speed: 是不是没有见过这个类,是的,这个类不常用,除非你经常做插件,需要跟Unity编辑器打交道,可能会用的到。这个对象可以通过以下方式获取:
1 | UnityEditor.Animations.AnimatorController ac = animator.runtimeAnimatorController as UnityEditor.Animations.AnimatorController; |
是不是觉得就要大功告成,然并卵!这个代码在第一行就会报错,就是animator.runtimeAnimatorController
无法转为UnityEditor.Animations.AnimatorController
类型,以前的版本是可以的,2018的版本是不行的,所以这种方法不行!
也就是说,通过speed方法,来达到动作的回放,是行不通的,Unity已经把这条路堵死了!
Time.timeScale(错误2)
Time.timeScale
可以加速,可以暂停,那Time.timeScale = -1
,会怎么样呢?直接提示:Time.timeScale
不能设为-1。而且Time.timeScale
会控制所有特效的播放,我只是想要控制当前角色动作的播放。所以这种方法不行!
Playback(错误3)
实在没有办法了,只能通过录像回放的形式来处理了。代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//录制
int frameCount = (int)(currentClip.length * currentClip.frameRate);
animator.speed = 0;
animator.StopPlayback();
animator.recorderStartTime = 0;
animator.StartRecording(frameCount);
animator.Update(0);
for (var i = 0; i < frameCount; i++)
{
animator.Update(1.0f / currentClip.frameRate);
}
animator.StopRecording();
animator.speed = 1;
.
.
.
//回放
animator.StartPlayback();
是不是觉得很完美,但是在实际使用中问题很多:
- 无法正确开始录制。录制时间开始的帧数无法确定,比如我想从idle状态转到attack状态,需要播放attak动作,我用
animator.GetCurrentAnimatorClipInfo(0)[0].clip.name
来判断是否到这一状态,然后开始录制,但是实际中,录制的动作总会少几帧。其实我觉得使用normalizeTime == 0
是可以用来判断 clip 是否已经开始播放了,可以准确的录制,但是我没有尝试,原因是录制回放会有一个很大的问题,就是下面这个问题。 - 事件帧会无限触发。暂时没有找到原因,我在某一帧加入事件后,在播放录像时该事件会无限触发,无解!
Animator.Play(正确)
就在绝望的时候,发现了一个接口:Animator.Play(string stateName, int layer = -1, float normalizedTime = float.NegativeInfinity)
,这个接口可以随意播放一个State,normalizedTime可以随意定位动作时间,normalizedTime是关键!!!需要注意的是,这个需要配合 animator.speed
使用,如果想要定位到某一帧,需要计算出该帧的 normalizedTime
, 并且设置 animator.speed=0
,即可实现定位到某一帧,并暂停!