赞
踩
问题可以细化为两种
为了确认这个问题的答案,我做了一个简单的测试,Idle为正常状态,Hit为角色的挨打动画,想直接看答案的可以直接看后面加粗的字
当我按下T键时,会播放Hit动画:
public class Test : MonoBehaviour { private Animator animator; private void Awake() { animator = GetComponent<Animator>(); } private void Update() { if (Input.GetKeyDown("t")) { animator.SetTrigger("hit"); } } }
模型的Hit状态上加了如下脚本:
public class OnHitState : StateMachineBehaviour
{
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("Enter Hit");
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("Exit Hit");
animator.ResetTrigger("hit");
}
}
正常按T,能从Idle状态播放挨打动画,再回到Idle状态,Log如下:
如果加上CrossFade呢,CrossFade可以选择两个状态,一种是CrossFade到Idle状态,一种是CrossFade到Hit状态。
更新后的Test脚本为:
private void Update() { if (Input.GetKeyDown("t")) { animator.SetTrigger("hit"); } if (Input.GetKeyDown("y")) { animator.CrossFade("Idle", 0.01f); } if (Input.GetKeyDown("u")) { animator.CrossFade("Hit", 0.01f); } }
为方便观察,给Idle也加个脚本:
public class OnIdleState : StateMachineBehaviour
{
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("Enter Idle");
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("Exit Idle");
}
}
Animator是这样的效果
OK,可以开始测试了
这是先按t,再按y后的效果,角色会立马切换回到Idle:
可以看出,CrossFade切换到另外一个状态,仍然会调用OnStateExit脚本(顺便注意到,Enter另外一个State的消息反而是先打印的,不过二者应该在同一帧)
那么如果CrossFade到自身的状态会怎么样呢?
这是测试的结果,值得注意的是,尽管按了t,再按u,也没有打印Exit Hit的动画,上面的Exit Hit打印信息是挨打动画播完了才自动打印的,也就是说:
CrossFade到自身动画的API不管用!!
随后又测到了一个奇怪的现象,我发现如果按完了 t 键(SetTrigger(“hit”)),触发了挨打动画后,迅速按 u 键(CrossFade(“Hit”, 0.01f)),能实现下述打印,为了方便查看,我加了两句帧数的显示情况:
思考后,发现Idle动画到Hit动画之间是有一个动画的切换过程的,如果此时这个转态过程按下了 u 键,这个转态也能转换到Hit状态,也就是说Animator不播放转态了,直接进入Hit的状态,这个时候由于状态介乎于Hit和Idle状态之间,会同时(准确的说是同一帧内)调用Hit和Idle的OnStateExit函数。
到这里,由于我做的游戏里面,角色要挨打,在挨打的OnStateExit的时候我做了相关逻辑处理,但是如果角色在挨打的时候,又挨打了,我需要重新播放该动画,而且希望OnStateExit函数能被调用,如果CrossFade到自身动画的API不管用,也不会走OnStateExit函数,那该怎么办呢?
想了个骚操作,看看这个行不行:
if (Input.GetKeyDown("u"))
{
animator.CrossFade("Idle", 0.000001f); //瞬间转换到Idle
animator.CrossFade("Hit", 0.000001f); //再转换回Hit,想要瞬间实现转态
}
然后发现没有,当角色挨打时,按u键,会立马切换到Idle状态,但是不会再走Hit了,因为这两个状态涉及时间的东西,所以我怀疑 animator.CrossFade不能连续使用,也有可能是由于HasExitTime的缘故。
既然方法行不通,就考虑别的把:
在UnityForum上看到了这个函数,完美的符合了我的情况,既能走OnStateExit函数,也能重新播放动画:
animator.Play("Hit", -1, 0);
看一下这个API:
所以在我的项目中,直接这么用就可以咯:
void OnParticleCollision(GameObject obj) { if (obj.tag == "Bullet") { //如果已经在播放挨打动画了 if (animator.GetCurrentAnimatorStateInfo(0).IsName("Hit")) { animator.Play("Hit", -1, 0);//重新播放动画,而且会调用OnStateExit } else { animator.SetTrigger("hit"); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。