You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 03:06:06