最近,公司想把旧的动画系统转到使用Mecanim来实现,让我来做技术预演。之前学习Unity3D的时候有接触过Mecanim,不过都忘了,所以又重新学了一遍。重新看了官网的Mecanim视频教程,凭我这半吊子英语水平也只是一知半解,所以又找了个视频看看,中国人的Mecanim教程。经过近1个半小时的努力,总算是实现了用Mecanim来控制各个动画的播放。可以做到Idle、Run、Attack、Hit和Die这五个状态的转换。当验收时主管提出但人物处于Hit状态时,再次受到Hit时动画要重头播放,故要重新返工。先是自己摸索一下Animator类是否支持动画重新播放,查看了文档,无奈官方文档 没有详细介绍Animator类,中文文档根本就没有介绍Animator类。现在就只能靠猜了,看来看去也就Animator下的StartPlayback()这个方法比较靠谱。可是试来试去还是不得法,最后就只能靠搜索引擎了。在这我不得不吐槽一下,做技术的还是用谷歌吧,百度搜不到的东西谷歌也许就能搜到。好吧,我就是用谷歌搜到了,网址在这,我会跟你说这是日本网站么。
这里说明一下,StartRecording()不是只回放一个状态的动画,而是可以记录n个状态的动画。如果要用这个来重播动作,需要自己用代码来控制,使其只播放要重播的状态的动画。如果要把这个状态的动画从最开始播放,那么前一个状态到要重播动画的状态的过渡动画就不要了,这个要在Animator Controller中进行设置,否则不可能做到从该状态的最开始重播动画(这个下面的代码没有实现)。
好吧,自己也实现了一把,送给有缘看到这篇博客的人,免去了找资料的痛苦。简化了Mecanim的状态,只有Idle和Hit两个状态。
后来发现这个方法不太好,哪里不好就不说了。说说新的方法:使用Animator.Play(state, layer, normalizedTime)这个方法,当normalizedTime为零时就可以做到重播的效果。
using UnityEngine;
using System.Collections;
public class SimpleExample : MonoBehaviour {
Animator anim = null;
AnimatorStateInfo currentBaseStage;
int idle = Animator.StringToHash("Base Layer.Idle");
int hit = Animator.StringToHash("Base Layer.Hit");
bool isHit = false;//在播放受击动画时是否再次受击 true: 受击
bool isPlayBack = false;//是否重播 true: 重播
// Use this for initialization
void Start () {
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
currentBaseStage = anim.GetCurrentAnimatorStateInfo(0);
if (currentBaseStage.nameHash == idle && !anim.IsInTransition(0))
{
anim.SetBool("hit", false);
isHit = false;
}
//hit
if (!isHit && Input.GetKey(KeyCode.H) && !anim.IsInTransition(0) && currentBaseStage.nameHash == idle)
{
anim.SetBool("hit", true);
anim.StartRecording(0);//frameCount为记录的帧数,0表示用StopRecording()来停止记录
isHit = true;
}
if (isHit && Input.GetKey(KeyCode.H) && currentBaseStage.nameHash == hit)
{
//二次受击
isPlayBack = true;
anim.StopRecording();//停止记录重播
anim.StartPlayback();//开始重播
anim.playbackTime = 0f;//从0s开始重播
}
//设置现在重播时播放的时间
if (isPlayBack)
{
float newPlaybackTime = anim.playbackTime + Time.deltaTime;
if (newPlaybackTime > anim.recorderStopTime) {
newPlaybackTime = 0;
anim.StopPlayback();
isPlayBack = false;
}
anim.playbackTime = newPlaybackTime;
}
}
}