Unity导航网格

1. 导航网格工具概述

1.1 基本概念

  • 导航网格(Navigation Mesh):Unity内置的AI寻路系统
  • 作用:为游戏中的AI角色提供自动寻路能力
  • 特点:可视化编辑、实时预览、性能优化

1.2 四个核心模块

1.2.1 Agents(代理页签)
  • 作用:用于配置寻路代理信息
  • 功能:定义AI角色的物理属性和移动参数
  • 主要设置
    • Agent Types:代理类型(如Humanoid)
    • Name:代理名称
    • Radius:代理半径(影响寻路精度)
    • Height:代理高度(决定可通过的通道高度)
    • Step Height:可跨越的台阶高度
    • Max Slope:可攀爬的最大坡度
1.2.2 Areas(导航地区页签)
  • 作用:配合Object页签使用,定义导航区域类型
  • 功能:设置不同区域的寻路消耗和通行规则
  • 主要设置
    • Name:区域名字,用于标识不同类型的导航区域
    • Cost:寻路消耗,数值越高AI越不愿意走该区域
  • 应用场景:区分道路、草地、水域等不同地形类型
1.2.3 Bake(导航数据烘焙页签)
  • 作用:生成导航网格数据
  • 功能:根据场景几何体和代理设置计算可行走区域
  • 核心参数
    • Agent Properties:代理属性设置
      • Agent Radius:代理半径(0.5)
      • Agent Height:代理高度(2)
      • Max Slope:最大坡度(45°)
      • Step Height:最小楼梯高度(0.4)
    • Generated Off Mesh Links:生成非网格连接
      • Drop Height:掉落高度(0)
      • Jump Distance:跳跃距离(0)
    • Advanced Settings:高级设置
      • Voxel Size:立体像素大小(影响精度和性能)
      • Min Region Area:最小区域面积(2)
      • Height Mesh:高度网格构建开关
1.2.4 Object(场景对象设置页签)
  • 作用:配置场景中具体对象的导航属性
  • 功能:设置哪些对象参与导航网格生成
  • 主要设置
    • Scene Filter:场景过滤器,配合Hierarchy窗口使用
      • All:显示场景上所有对象
      • Mesh Renderers:显示挂载网格渲染器的对象
      • Terrains:显示挂载地形脚本的对象
    • Navigation Static:导航静态物体开关
    • Generate OffMeshLinks:生成网格连接点开关
    • Navigation Area:导航区域选择,配合Areas页签使用

1.3 工作流程

┌─────────────────────────────────────────────────────────────┐
│                    Unity导航网格工作流程                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │  配置代理   │───▶│  设置区域   │───▶│  对象配置   │     │
│  │  Agents     │    │  Areas      │    │  Object     │     │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│                                                             │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐     │
│  │  烘焙生成   │◀───│  预览检查   │◀───│  应用寻路   │     │
│  │  Bake       │    │  Scene View │    │  NavMesh    │     │
│  └─────────────┘    └─────────────┘    └─────────────┘     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.4 使用注意事项

  • 性能考虑:Voxel Size越小精度越高,但内存占用和烘焙时间会显著增加
  • 区域设置:合理设置Navigation Area和Cost值,避免AI选择不合理的路径
  • 对象标记:确保需要参与导航的对象都正确标记为Navigation Static
  • 烘焙优化:大型场景建议分区域烘焙,提高工作效率

2. 导航网格组件

2.1 组件架构概述

  • 核心组件:构成Unity导航系统的功能模块
  • 作用:为AI角色提供寻路、避障、路径规划等能力
  • 特点:模块化设计、易于配置、性能优化

2.2 主要组件类型

2.2.1 NavMeshAgent(导航网格代理)
  • 作用:AI角色的核心寻路组件
  • 功能:自动寻路、避障、路径规划
  • 主要属性
    • Agent Type:代理类型设置
    • Speed:移动速度
    • Angular Speed:旋转速度
    • Acceleration:加速度
    • Stopping Distance:停止距离
    • Radius:代理半径
    • Height:代理高度
2.2.1.1 基础代码示例
using UnityEngine;
using UnityEngine.AI;

public class NavMeshAgentDemo : MonoBehaviour
{
    private NavMeshAgent agent;
    public Transform target; // 目标位置
    
    void Start()
    {
        // 获取或添加NavMeshAgent组件
        agent = GetComponent<NavMeshAgent>();
        if (agent == null)
        {
            agent = gameObject.AddComponent<NavMeshAgent>();
        }
        
        // 基础属性设置
        agent.speed = 5f;                    // 移动速度
        agent.angularSpeed = 120f;           // 旋转速度
        agent.acceleration = 8f;             // 加速度
        agent.stoppingDistance = 1f;         // 停止距离
        agent.radius = 0.5f;                 // 代理半径
        agent.height = 2f;                   // 代理高度
    }
    
    void Update()
    {
        // 设置目标位置
        if (target != null)
        {
            agent.SetDestination(target.position);
        }
    }
}
2.2.1.2 高级功能代码示例
using UnityEngine;
using UnityEngine.AI;

public class AdvancedNavMeshAgent : MonoBehaviour
{
    private NavMeshAgent agent;
    public Transform[] waypoints; // 路径点数组
    private int currentWaypoint = 0;
    
    void Start()
    {
        agent = GetComponent<NavMeshAgent>();
        SetupAgent();
    }
    
    void SetupAgent()
    {
        // 高级属性设置
        agent.avoidancePriority = 50;        // 避障优先级
        agent.autoTraverseOffMeshLink = true; // 自动通过OffMeshLink
        agent.autoRepath = true;             // 自动重新寻路
        agent.pathfindingIterationsPerFrame = 100; // 每帧寻路迭代次数
    }
    
    void Update()
    {
        // 巡逻逻辑
        if (waypoints.Length > 0)
        {
            if (agent.remainingDistance < 0.5f)
            {
                currentWaypoint = (currentWaypoint + 1) % waypoints.Length;
                agent.SetDestination(waypoints[currentWaypoint].position);
            }
        }
    }
    
    // 手动寻路到指定位置
    public void MoveTo(Vector3 destination)
    {
        if (agent.isOnNavMesh)
        {
            agent.SetDestination(destination);
        }
    }
    
    // 检查是否到达目标
    public bool HasReachedDestination()
    {
        return !agent.pathPending && 
               agent.remainingDistance <= agent.stoppingDistance;
    }
    
    // 停止移动
    public void StopMoving()
    {
        agent.isStopped = true;
    }
    
    // 恢复移动
    public void ResumeMoving()
    {
        agent.isStopped = false;
    }
}
2.2.2 NavMeshObstacle(导航网格障碍物)
  • 作用:动态障碍物组件
  • 功能:实时更新导航网格,创建动态障碍
  • 主要属性
    • Shape:障碍物形状
    • Size:障碍物尺寸
    • Carving:是否雕刻导航网格
    • Movement Threshold:移动阈值
2.2.2.1 动态障碍物组件的用途
  • 游戏场景应用:在游戏场景中,经常有这样的功能:
    • 场景中有一扇门,如果这扇门没有被破坏,AI角色无法自动寻路到门后的场景
    • 只有当门被破坏后,AI角色才能通过到下一个场景
    • 像门这样的对象本身不需要进行寻路,所以不需要给它们添加NavMeshAgent脚本
    • 在这种情况下,使用"动态障碍物组件"(NavMeshObstacle)来实现这个功能
2.2.2.2 动态障碍物组件的使用方法
  • 基本设置:为需要动态阻挡AI的对象添加NavMeshObstacle组件
  • 形状配置:根据对象的实际形状设置障碍物的几何形状
  • 尺寸调整:调整障碍物的尺寸以准确反映阻挡范围
  • 雕刻设置:启用Carving功能,让障碍物能够实时更新导航网格
  • 移动阈值:设置Movement Threshold,控制障碍物移动多少距离后才更新导航网格
2.2.2.3 代码示例
using UnityEngine;
using UnityEngine.AI;

public class DynamicObstacle : MonoBehaviour
{
    private NavMeshObstacle obstacle;
    
    void Start()
    {
        // 获取或添加NavMeshObstacle组件
        obstacle = GetComponent<NavMeshObstacle>();
        if (obstacle == null)
        {
            obstacle = gameObject.AddComponent<NavMeshObstacle>();
        }
        
        // 基础设置
        obstacle.shape = NavMeshObstacleShape.Box; // 设置为盒子形状
        obstacle.size = Vector3.one; // 设置尺寸
        obstacle.carving = true; // 启用雕刻功能
        obstacle.movementThreshold = 0.1f; // 移动阈值
    }
    
    // 动态启用/禁用障碍物
    public void SetObstacleActive(bool active)
    {
        if (obstacle != null)
        {
            obstacle.carving = active;
        }
    }
    
    // 动态调整障碍物尺寸
    public void UpdateObstacleSize(Vector3 newSize)
    {
        if (obstacle != null)
        {
            obstacle.size = newSize;
        }
    }
    
    // 门被破坏时的处理
    public void OnDoorDestroyed()
    {
        // 禁用障碍物,让AI可以通过
        SetObstacleActive(false);
        
        // 或者直接销毁组件
        if (obstacle != null)
        {
            Destroy(obstacle);
        }
    }
}
2.2.3 NavMeshSurface(导航网格表面)
  • 作用:生成和管理导航网格表面
  • 功能:动态生成、更新导航网格
  • 主要属性
    • Collection Object:收集对象
    • Use Geometry:使用几何体类型
    • Default Area:默认区域
    • Layer Mask:层级遮罩
2.2.4 NavMeshLink(导航网格连接)
  • 作用:连接分离的导航网格区域
  • 功能:创建跳跃、掉落等特殊移动连接
  • 主要属性
    • Start Point:起始点
    • End Point:结束点
    • Width:连接宽度
    • Cost Override:成本覆盖
2.2.4.1 详细属性说明
  • Start(起始点):连接点的起始位置,指定为Transform组件
  • End(结束点):连接点的结束位置,指定为Transform组件
  • Cost Override(覆盖消耗值)
    • 负值或0:使用所属Area的寻路消耗
    • 正值:Area的寻路消耗 × 正值 = 该连接点的寻路消耗
    • 用途:自定义连接点的寻路消耗,解决"步行"和"连接点"都能到达目标,但希望优先选择步行区域的情况
  • Bi Directional(双向连接点)
    • 启用:可以从Start到End,也可以从End到Start
    • 禁用:只能从Start到End单向通行
  • Activated(启用连接点):是否启用该连接点,禁用时在自动寻路中无效
  • Auto Update Positions(自动更新位置)
    • 启用:起始和结束位置变化时,导航网格自动更新
    • 禁用:即使位置变化,仍按初始位置计算
  • Navigation Area(导航区域):指定连接点所属的导航区域类型,影响哪些代理可以使用以及默认消耗
2.2.4.2 代码示例
using UnityEngine;
using UnityEngine.AI;

public class NavMeshLinkController : MonoBehaviour
{
    public Transform startPoint;
    public Transform endPoint;
    public float costOverride = -1f;
    public bool biDirectional = true;
    public bool activated = true;
    public bool autoUpdatePositions = false;
    
    private OffMeshLink offMeshLink;
    
    void Start()
    {
        CreateOffMeshLink();
    }
    
    void CreateOffMeshLink()
    {
        // 创建OffMeshLink组件
        offMeshLink = gameObject.AddComponent<OffMeshLink>();
        
        // 设置起始和结束点
        offMeshLink.startTransform = startPoint;
        offMeshLink.endTransform = endPoint;
        
        // 设置连接点属性
        offMeshLink.costOverride = costOverride;
        offMeshLink.biDirectional = biDirectional;
        offMeshLink.activated = activated;
        offMeshLink.autoUpdatePositions = autoUpdatePositions;
        
        // 设置导航区域(默认为Walkable)
        offMeshLink.area = 0; // 0 = Walkable
    }
    
    // 动态启用/禁用连接点
    public void SetLinkActive(bool active)
    {
        if (offMeshLink != null)
        {
            offMeshLink.activated = active;
        }
    }
    
    // 动态设置成本覆盖
    public void SetCostOverride(float cost)
    {
        if (offMeshLink != null)
        {
            offMeshLink.costOverride = cost;
        }
    }
    
    // 检查连接点是否有效
    public bool IsLinkValid()
    {
        return offMeshLink != null && 
               offMeshLink.activated && 
               offMeshLink.startTransform != null && 
               offMeshLink.endTransform != null;
    }
}
2.2.4.3 使用场景示例
// 跳跃连接点示例
public class JumpLink : MonoBehaviour
{
    public Transform jumpStart;
    public Transform jumpEnd;
    public float jumpCost = 2f; // 跳跃消耗较高
    
    void Start()
    {
        var link = gameObject.AddComponent<OffMeshLink>();
        link.startTransform = jumpStart;
        link.endTransform = jumpEnd;
        link.costOverride = jumpCost;
        link.biDirectional = true;
        link.activated = true;
    }
}

// 单向连接点示例(如滑梯)
public class SlideLink : MonoBehaviour
{
    public Transform slideStart;
    public Transform slideEnd;
    
    void Start()
    {
        var link = gameObject.AddComponent<OffMeshLink>();
        link.startTransform = slideStart;
        link.endTransform = slideEnd;
        link.costOverride = 0.5f; // 滑梯消耗较低
        link.biDirectional = false; // 单向滑行
        link.activated = true;
    }
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐