如何在Unity FPS游戏中实现敌人受击时临时停止追逐玩家的功能
解决方案
核心问题分析
你现有代码的核心问题有3个:
- Update方法每帧强制设置NavMeshAgent的目标点,且没有「受击/死亡状态下跳过导航逻辑」的判断
- 只做了受击时禁用NavMeshAgent的逻辑,没有对应「动画播放完毕后重新启用Agent」的逻辑
- 没有获取动画时长来控制状态时长,导致停止移动的时间和动画不同步
- 用Bool类型控制isHit状态需要手动重置,容易出现状态卡滞
第一步:调整Animator参数
打开你的Animator控制器,将isHit参数从Bool类型修改为Trigger类型。Trigger类型触发后会自动重置,不需要手动设置为false,能避免状态异常。
第二步:修改业务代码
你可以用Unity协程来控制状态的等待时长,以下是修改后的完整代码:
// 先缓存组件引用,不要每帧调用GetComponent,避免性能损耗 private NavMeshAgent navAgent; private Animator enemyAnimator; // 新增状态标记,避免导航逻辑在异常状态下执行 private bool isHurt = false; private bool isDead = false; void Awake() { // 初始化时就获取组件缓存 navAgent = GetComponent<NavMeshAgent>(); enemyAnimator = GetComponent<Animator>(); } void Update() { // 只有非受击、非死亡状态下才执行导航逻辑 if (!isHurt && !isDead && navAgent.enabled) { navAgent.destination = player.transform.position; enemyAnimator.SetBool("isRunning", navAgent.velocity.magnitude > 1); } } public void TakeDamage(float damage) { if (isDead) return; // 已经死亡的话不再执行受击逻辑 health -= damage; Debug.Log("Enemy health: " + health); if(health <= 0) { isDead = true; navAgent.enabled = false; enemyAnimator.SetBool("isDying", true); // 启动协程,等死亡动画播完再销毁对象 StartCoroutine(WaitForDeathAnimation()); return; } // 触发受击动画 enemyAnimator.SetTrigger("isHit"); StartCoroutine(WaitForHitAnimation()); } // 受击动画等待协程 IEnumerator WaitForHitAnimation() { isHurt = true; navAgent.enabled = false; // 等待一帧,确保Animator已经切换到受击状态 yield return null; // 获取当前受击动画的时长,0是Base Layer的索引,如果你用了别的层请修改为对应索引 float hitAnimationLength = enemyAnimator.GetCurrentAnimatorStateInfo(0).length; // 等待对应动画时长 yield return new WaitForSeconds(hitAnimationLength); // 受击动画结束,恢复移动 navAgent.enabled = true; isHurt = false; } // 死亡动画等待协程 IEnumerator WaitForDeathAnimation() { // 等待一帧确保动画切换完成 yield return null; // 获取死亡动画时长 float deathAnimationLength = enemyAnimator.GetCurrentAnimatorStateInfo(0).length; yield return new WaitForSeconds(deathAnimationLength); // 动画播放完毕后销毁对象 Destroy(gameObject); }
注意事项
- 确保你的受击、死亡动画都没有勾选
Loop Time选项,否则协程会按照循环时长无限等待 - 如果你的动画状态存在过渡(Transition),想要更精准的时长控制,可以在获取时长时加上过渡时间,或者直接在动画编辑器里给受击、死亡动画加结束事件,事件触发时执行恢复移动/销毁的逻辑
- 如果你的受击/死亡动画不在默认的Base Layer,把
GetCurrentAnimatorStateInfo的参数改为对应动画层的索引即可
内容的提问来源于stack exchange,提问作者Niko Gamulin
相关产品推荐
相关产品推荐

