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

Unity敌人AI逻辑问题:实现步行触发后才可切换奔跑状态

问题分析与修复方案

原代码核心问题

  • 错误手动调用Unity回调:OnBecameVisible()是Unity内置的状态回调,仅在对象从不可见变为可见时触发一次,无需在Update()中循环调用,这会导致逻辑触发时机完全混乱。
  • 状态逻辑缺失:未实现“敌人距离玩家2米以内切换奔跑”的需求,且isWalking的状态切换逻辑模糊,无法完成行走/奔跑的正确切换。
  • 不可见状态处理错误:OnBecomeInvisible()直接禁用脚本会导致敌人重新可见时无法恢复逻辑,应改为停止移动并重置状态。
  • 输入检测位置错误:空格键输入需在Update()中持续监听,而非仅在可见状态变化时检测,否则无法捕捉可见状态下的多次按键操作。

修正后的完整代码

using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
    public NavMeshAgent enemy;
    public Transform player;

    public float speedWalk = 6f;
    public float speedRun = 12f; // 原60f速度过高,调整为合理值
    public float chaseDelay = 2f;
    public float runTriggerDistance = 2f; // 触发奔跑的距离阈值

    private bool isWalking;
    private bool isRunning;
    private Renderer m_Renderer;
    private Coroutine chaseCoroutine;

    private void Start()
    {
        m_Renderer = GetComponent<Renderer>();
        isWalking = false;
        isRunning = false;
        enemy.speed = speedWalk;
        enemy.isStopped = true; // 初始状态停止移动
    }

    private void OnBecameVisible()
    {
        // 敌人可见时恢复移动权限
        enemy.isStopped = false;
    }

    private void OnBecameInvisible()
    {
        // 敌人不可见时停止移动并重置所有状态
        enemy.isStopped = true;
        isWalking = false;
        isRunning = false;
        if (chaseCoroutine != null)
        {
            StopCoroutine(chaseCoroutine);
            chaseCoroutine = null;
        }
    }

    private IEnumerator StartChaseWithDelay()
    {
        yield return new WaitForSeconds(chaseDelay);
        // 延迟结束后进入行走状态
        isWalking = true;
        isRunning = false;
        enemy.speed = speedWalk;
        enemy.SetDestination(player.position);
    }

    private void Update()
    {
        // 仅当敌人可见时处理逻辑
        if (!m_Renderer.isVisible)
            return;

        float distanceToPlayer = Vector3.Distance(transform.position, player.position);

        // 处理空格键单次按下事件
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (!isWalking && !isRunning)
            {
                // 未移动状态下启动延迟追逐
                if (chaseCoroutine == null)
                {
                    chaseCoroutine = StartCoroutine(StartChaseWithDelay());
                }
            }
            else if (isWalking)
            {
                // 行走状态下切换为奔跑
                isWalking = false;
                isRunning = true;
                enemy.speed = speedRun;
                enemy.SetDestination(player.position);
            }
        }

        // 距离玩家2米以内自动切换奔跑
        if ((isWalking || isRunning) && distanceToPlayer <= runTriggerDistance)
        {
            isWalking = false;
            isRunning = true;
            enemy.speed = speedRun;
            enemy.SetDestination(player.position);
        }

        // 持续更新目标位置,追踪移动的玩家
        if (isWalking || isRunning)
        {
            enemy.SetDestination(player.position);
        }
    }
}

关键修改说明

  • 回调逻辑规范:仅保留OnBecameVisible()和OnBecameInvisible()的状态切换作用,不再手动调用。
  • 状态清晰划分:新增isRunning变量,明确区分停止、行走、奔跑三种状态。
  • 输入逻辑优化:使用Input.GetKeyDown()检测单次按键,避免持续按住触发重复操作,且将输入检测放在Update()中持续监听。
  • 距离触发实现:添加距离阈值变量,实时计算敌人与玩家的距离,满足“2米以内切换奔跑”的需求。
  • 不可见状态修复:改为停止移动并重置状态,而非禁用脚本,确保敌人重新可见时能正常恢复逻辑。
  • 目标持续追踪:在移动状态下持续更新目标位置,保证敌人能跟随移动的玩家。

内容的提问来源于stack exchange,提问作者user21241519

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:31:01