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

Unity中如何让Nav Mesh Agents将彼此视为障碍物?

Unity NavMeshAgent 单位互避与自Obstacle忽略方案

问题核心

  • NavMeshAgent默认不将其他Agent视为障碍物,导致单位间推挤甚至穿模,无法实现《星际争霸》《魔兽争霸》《Dota》类的单位互避效果
  • 同一对象同时挂载NavMeshAgent与NavMeshObstacle时,会因Agent原点与不可行走区域重叠出现随机抖动;调整偏移量仅能临时解决,其他单位靠近时重叠问题复现
  • 增大Agent半径无法解决重叠问题,核心需求是同一对象共存Agent与Obstacle,且Agent忽略自身的Obstacle

可行解决方案

方法1:动态切换NavMeshObstacle雕刻状态

这是最直接的方案,利用carveOnlyStationary属性让单位移动时不生成自身障碍物,静止时成为阻挡:

  • 给目标单位同时挂载NavMeshAgent和NavMeshObstacle组件
  • 在Inspector面板设置NavMeshObstacle.carveOnlyStationary = true,默认关闭carving选项
  • 通过脚本监控Agent移动状态,动态开启/关闭Obstacle的雕刻功能:
using UnityEngine;
using UnityEngine.AI;

public class UnitNavManager : MonoBehaviour
{
    private NavMeshAgent _agent;
    private NavMeshObstacle _obstacle;

    void Start()
    {
        _agent = GetComponent<NavMeshAgent>();
        _obstacle = GetComponent<NavMeshObstacle>();
        _obstacle.carveOnlyStationary = true;
        _obstacle.carving = false;
    }

    void Update()
    {
        bool isMoving = _agent.velocity.magnitude > 0.1f;
        // 移动时关闭自身障碍物雕刻,避免与Agent冲突;静止时开启,阻挡其他单位
        _obstacle.carving = !isMoving;
    }
}

方法2:分层隔离自身Agent与Obstacle

通过Layer和子对象分离组件,实现Agent忽略自身Obstacle:

  • 创建两个自定义Layer:UnitAgent和UnitObstacle
  • 将挂载NavMeshAgent的主对象Layer设为UnitAgent
  • 创建子对象,将NavMeshObstacle挂载到子对象上,子对象Layer设为UnitObstacle
  • 在NavMesh设置中,为UnitObstacle指定专属的NavMeshArea(比如自定义UnitBlock区域)
  • 将主对象的NavMeshAgent.areaMask设置为不包含UnitBlock区域,让Agent忽略自身Obstacle生成的不可行走区域
  • 其他单位的Obstacle同样使用UnitObstacleLayer,确保能被当前Agent检测到,实现互避

方法3:自定义动态互避逻辑(补充增强)

如果默认NavMesh避障效果不够细腻,可以结合碰撞检测实现单位间的排斥力:

  • 给每个单位添加Sphere Collider(勾选Is Trigger),设置合适的检测半径
  • 编写脚本检测周围同层单位,计算排斥力并施加到Agent上:
using UnityEngine;
using UnityEngine.AI;

public class UnitRepel : MonoBehaviour
{
    private NavMeshAgent _agent;
    public float repelForce = 6f;
    public float repelRange = 1.8f;

    void Start()
    {
        _agent = GetComponent<NavMeshAgent>();
    }

    void FixedUpdate()
    {
        Collider[] nearbyUnits = Physics.OverlapSphere(transform.position, repelRange, LayerMask.GetMask("Unit"));
        foreach (Collider unitCollider in nearbyUnits)
        {
            if (unitCollider.gameObject != gameObject)
            {
                Vector3 repelDir = (transform.position - unitCollider.transform.position).normalized;
                _agent.AddForce(repelDir * repelForce, ForceMode.VelocityChange);
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 01:57:33