【unity游戏开发】彻底理解AnimatorStateInfo,获取真实动画长度

前言

前置知识:设置参数后,下一个循环才会切换对应动画,所以在下一个循环获取真实的动画长度

AnimatorStateInfo是结构体!值类型,要不断重复获取才是最新的

主要是自动设置trigger切换的动画自动切回上一个动画,需要在异步中等待动画结束,于是用传统方式:

csharp 复制代码
//上一个动画没有退出时间,直接等一个循环就是真实动画
await UniTask.Yield(PlayerLoopTiming.Update);

//上一个动画有退出时间
AnimatorStateInfo currentAm = animator.GetCurrentAnimatorStateInfo(0);
while (currentAm.normalizedTime < 1f || animator.IsInTransition(0))
			{
				await UniTask.Yield(PlayerLoopTiming.Update);
			}

但是我用的连击动画为了好的手感将动画结束时间提前,这就导致进入这里的currentAm 可能是上一次的攻击动画

所以直接判断上一个动画是否执行完毕

AnimatorStateInfo重要属性

  • normalizedTime :动画播放进度,播放完则是1,每次循环+1,需要注意不循环的动画可能只到9.x就切换了
  • shortNameHash:状态名字 转换成的hash值
  • length:动画时长,单位秒
  • IsName: 将字符串转为hash进行判断

代码

需要约定状态名,我的枚举名和状态名相等,连击的攻击则是枚举名 + combo数 + 1,连击参数是连击状态名+Combo

csharp 复制代码
private async UniTask WaitForAnimator(Animator animator)
		{
			// 注意参数的设置也是下一轮才生效,所以先等一轮
			// 上一个动画没有退出时间,直接等一个循环就是真实动画
			await UniTask.Yield(PlayerLoopTiming.Update);
			//获取唯一状态标识
			var preStateKey = currentState.state.ToString().Contains("DoubleAttack") ?
			currentState.state.ToString() + animator.GetInteger(currentState.state.ToString() + "Combo") : lastState.state.ToString();
			Debug.Log(animator.GetInteger(currentState.state.ToString() + "Combo"));
			AnimatorStateInfo currentAm = animator.GetCurrentAnimatorStateInfo(0);
			//等到上一个攻击动画执行完毕
			while (currentAm.IsName(preStateKey))
			{
				await UniTask.Yield(PlayerLoopTiming.Update);
				currentAm = animator.GetCurrentAnimatorStateInfo(0);
			}

			var duration = currentAm.length;
			float preProcessTime = currentState.state.ToString().Contains("Attack") ? duration * 0.2f : 0; // 计算提前处理时间(动画总时长的 25%)
			// 等待动画完成
			float waitTime = duration - preProcessTime;
			if (waitTime > 0)
				await UniTask.Delay((int)(waitTime * 1000), DelayType.Realtime, PlayerLoopTiming.Update);
// 所有动画完成后切换状态
			ChangeState(lastBoolState);
		}
也可以直接保存shortNameHash作为状态名称 不推荐
csharp 复制代码
private Dictionary<String, int> animalNameHashDic = new();
private async UniTask WaitForAnimator(Animator animator)
		{
			//获取唯一状态标识
			var key = currentState.state.ToString().Contains("Attack") ?
			currentState.state.ToString() + GameMgr.Instance.player.ComboCounter : currentState.state.ToString();

			AnimatorStateInfo currentAm = animator.GetCurrentAnimatorStateInfo(0);
			//真实的动画长度:shortNameHash相等
			if (animalNameHashDic.ContainsKey(key))
			{
				// Debug.Log(currentAm.shortNameHash);
				while (animalNameHashDic[key] == currentAm.shortNameHash)
				{
					await UniTask.Yield(PlayerLoopTiming.Update);
					currentAm = animator.GetCurrentAnimatorStateInfo(0);
				}
			}
			else
			{
				// 第一次就是真实的
				if (!animalNameHashDic.ContainsKey(key))
					animalNameHashDic.Add(key, currentAm.shortNameHash);
			}

			var duration = currentAm.length;
			float preProcessTime = currentState.state.ToString().Contains("Attack") ? duration * 0.2f : 0; // 计算提前处理时间(动画总时长的 25%)
			// 等待动画完成
			float waitTime = duration - preProcessTime;
			if (waitTime > 0)
				await UniTask.Delay((int)(waitTime * 1000), DelayType.Realtime, PlayerLoopTiming.Update);
		}
相关推荐
DongQiShanRen12 分钟前
裁决台账双向互校(下):台账哈希链、三向对账与最小落地
人工智能·深度学习·算法·目标跟踪·自然语言处理·rust·哈希算法
翼龙云_cloud37 分钟前
阿里云国际代理商:ECS部署DeepSeek大模型指南
服务器·阿里云·大模型·云计算
2401_868534781 小时前
安全故障分析
服务器·网络·安全
xixiaoyunya1 小时前
集中保护多台电脑:搭建内网备份服务器的完整实操方案
运维·服务器·电脑
她说彩礼65万1 小时前
C语言 const的使用
java·服务器·c语言
JEECG低代码平台2 小时前
不买服务器也能异地组网:开源 P2WLAN 把两地电脑“插“进同一台路由器
运维·服务器·开源·开源软件
cehuishi95272 小时前
测绘外业调查如何正确的开展
运维·服务器·网络
lisanmengmeng2 小时前
NRPE 添加命令(三)
java·linux·服务器
小贺儿开发2 小时前
Unity 局域网遥控幻灯片展示工具 3.0
科技·http·unity·工具·ppt·通信·网页
人工智能培训2 小时前
数字孪生驱动大模型工业知识库:为具身机器人植入领域专业经验
大数据·linux·服务器·前端·人工智能