第5章 Unity导航网格系统高级应用

5.1 导航网格系统概述

导航网格(NavMesh)是现代游戏AI导航系统的核心技术,它通过将可行走区域转换为多边形网格,为AI角色提供智能路径规划的基础。Unity引擎的NavMesh系统经过多年发展,在2021版本中提供了更强大、更灵活的API,使开发者能够实现复杂的导航需求。

导航网格的核心原理是将3D游戏场景中的可行走表面转换为2.5D的三角形网格表示。这种转换允许AI系统快速计算两点之间的可行走路径,同时避开障碍物和不可行走区域。与传统基于路点的导航系统相比,导航网格具有以下优势:

  1. 动态适应性:能够处理复杂地形和动态变化的场景
  2. 路径质量:生成平滑、自然的移动路径
  3. 性能优化:预计算导航数据,运行时快速查询
  4. 多代理支持:支持不同类型角色的差异化导航需求

在商业游戏项目中,导航网格系统通常用于实现以下功能:

  • NPC的寻路和移动
  • 敌人的追击和包围行为
  • 玩家的自动寻路辅助
  • 群体行为的路径规划
  • 动态环境的自适应导航

5.2 配置与初始化导航网格开发环境

在开始使用Unity的导航网格系统之前,需要进行正确的环境配置和初始化设置。这一过程包括导入必要的包、配置项目设置以及建立开发工作流程。

5.2.1 导航系统包导入与配置

Unity 2021.3.8f1c1中,导航系统通过两个主要包提供:AI Navigation和AI Navigation Components。以下是详细的配置步骤:

using UnityEngine;
using UnityEngine.AI;
using System.Collections.Generic;

namespace NavigationSystem
{
    // 导航系统初始化管理器
    public class NavigationSystemInitializer : MonoBehaviour
    {
        [Header("导航系统设置")]
        [SerializeField] private bool autoInitialize = true;
        [SerializeField] private NavigationSystemSettings systemSettings;
        
        private NavMeshData navMeshData;
        private List<NavMeshBuildSource> buildSources;
        private NavMeshBuildSettings buildSettings;
        
        private void Awake()
        {
            if (autoInitialize)
            {
                InitializeNavigationSystem();
            }
        }
        
        public void InitializeNavigationSystem()
        {
            Debug.Log("开始初始化导航系统...");
            
            // 步骤1:检查导航系统可用性
            if (!IsNavigationSystemAvailable())
            {
                Debug.LogError("导航系统不可用,请确保已导入AI Navigation包");
                return;
            }
            
            // 步骤2:加载或创建导航系统设置
            LoadNavigationSettings();
            
            // 步骤3:收集场景中的导航几何体
            CollectNavigationGeometry();
            
            // 步骤4:配置代理类型
            ConfigureAgentTypes();
            
            // 步骤5:构建初始导航网格
            BuildInitialNavMesh();
            
            Debug.Log("导航系统初始化完成");
        }
        
        private bool IsNavigationSystemAvailable()
        {
            // 检查必要的组件和类型是否可用
            try
            {
                var testAgent = new NavMeshAgent();
                return true;
            }
            catch (System.Exception)
            {
                return false;
            }
        }
        
        private void LoadNavigationSettings()
        {
            // 如果未提供设置,创建默认设置
            if (systemSettings == null)
            {
                systemSettings = ScriptableObject.CreateInstance<NavigationSystemSettings>();
                ConfigureDefaultSettings(systemSettings);
                Debug.Log("使用默认导航系统设置");
            }
            
            // 应用设置到导航系统
            ApplySystemSettings();
        }
        
        private void ConfigureDefaultSettings(NavigationSystemSettings settings)
        {
            settings.defaultAgentTypeID = 0;
            settings.buildHeightMesh = true;
            settings.autoRebuild = true;
            settings.rebuildInterval = 0.5f;
            settings.asyncBuild = true;
            
            // 默认代理设置
            settings.defaultAgentRadius = 0.5f;
            settings.defaultAgentHeight = 2.0f;
            settings.defaultAgentStepHeight = 0.4f;
            settings.defaultMaxSlope = 45.0f;
        }
        
        private void ApplySystemSettings()
        {
            // 配置全局导航网格设置
            NavMesh.pathfindingIterationsPerFrame = systemSettings.pathfindingIterationsPerFrame;
            NavMesh.avoidancePredictionTime = systemSettings.avoidancePredictionTime;
            
            // 设置自动重建
            if (systemSettings.autoRebuild)
            {
                StartCoroutine(AutoRebuildNavMesh());
            }
        }
        
        private System.Collections.IEnumerator AutoRebuildNavMesh()
        {
            while (true)
            {
                yield return new WaitForSeconds(systemSettings.rebuildInterval);
                
                if (NavMeshSurface.activeSurfaces.Count > 0)
                {
                    NavMeshSurface.UpdateActive();
                }
            }
        }
        
        private void CollectNavigationGeometry()
        {
            buildSources = new List<NavMeshBuildSource>();
            
            // 收集所有带有NavMeshSourceTag的几何体
            NavMeshSourceTag[] sourceTags = FindObjectsOfType<NavMeshSourceTag>();
            foreach (NavMeshSourceTag tag in sourceTags)
            {
                buildSources.AddRange(tag.Collect());
            }
            
            // 如果没有显式标记,收集所有带有MeshFilter的静态几何体
            if (buildSources.Count == 0)
            {
                CollectStaticGeometry();
            }
            
            Debug.Log($"收集到 {buildSources.Count} 个导航网格源");
        }
        
        private void CollectStaticGeometry()
        {
            MeshFilter[] meshFilters = FindObjectsOfType<MeshFilter>();
            foreach (MeshFilter filter in meshFilters)
            {
                // 只处理标记为静态的对象
                if (filter.gameObject.isStatic && filter.sharedMesh != null)
                {
                    NavMeshBuildSource source = new NavMeshBuildSource
                    {
                        shape = NavMeshBuildSourceShape.Mesh,
                        sourceObject = filter.sharedMesh,
                        transform = filter.transform.localToWorldMatrix,
                        area = 0 // 可行走区域
                    };
                    
                    buildSources.Add(source);
                }
            }
        }
        
        private void ConfigureAgentTypes()
        {
            // 获取或创建代理类型设置
            var agentTypes = NavMesh.GetSettingsByIndex(0);
            
            // 配置默认人类代理
            if (agentTypes.agentTypeID == -1)
            {
                CreateDefaultAgentType();
            }
            
            // 配置多个代理类型(人类、车辆、飞行器等)
            ConfigureMultipleAgentTypes();
        }
        
        private void CreateDefaultAgentType()
        {
            NavMeshBuildSettings settings = new NavMeshBuildSettings
            {
                agentTypeID = 0,
                agentRadius = systemSettings.defaultAgentRadius,
                agentHeight = systemSettings.defaultAgentHeight,
                agentSlope = systemSettings.defaultMaxSlope,
                agentClimb = systemSettings.defaultAgentStepHeight,
                minRegionArea = 2.0f,
                tileSize = 256
            };
            
            NavMesh.AddSettings(settings);
        }
        
        private void ConfigureMultipleAgentTypes()
        {
            // 人类代理(默认)
            NavMeshBuildSettings humanSettings = NavMesh.CreateSettings();
            humanSettings.agentTypeID = 0;
            humanSettings.agentRadius = 0.5f;
            humanSettings.agentHeight = 2.0f;
            humanSettings.agentSlope = 45.0f;
            humanSettings.agentClimb = 0.4f;
            humanSettings.agentTypeID = 0;
            
            // 小型代理(如老鼠、昆虫)
            NavMeshBuildSettings smallSettings = NavMesh.CreateSettings();
            smallSettings.agentTypeID = 1;
            smallSettings.agentRadius = 0.1f;
            smallSettings.agentHeight = 0.5f;
            smallSettings.agentSlope = 60.0f;
            smallSettings.agentClimb = 0.2f;
            
            // 大型代理(如巨人、车辆)
            NavMeshBuildSettings largeSettings = NavMesh.CreateSettings();
            largeSettings.agentTypeID = 2;
            largeSettings.agentRadius = 1.0f;
            largeSettings.agentHeight = 3.0f;
            largeSettings.agentSlope = 30.0f;
            largeSettings.agentClimb = 0.6f;
            
            // 添加到导航系统
            NavMesh.AddSettings(humanSettings);
            NavMesh.AddSettings(smallSettings);
            NavMesh.AddSettings(largeSettings);
        }
        
        private void BuildInitialNavMesh()
        {
            if (buildSources == null || buildSources.Count == 0)
            {
                Debug.LogWarning("没有找到导航网格源,跳过初始构建");
                return;
            }
            
            // 使用默认代理设置
            buildSettings = NavMesh.CreateSettings();
            buildSettings.agentTypeID = 0;
            
            // 定义导航网格的边界(整个场景)
            Bounds bounds = CalculateSceneBounds();
            
            // 异步构建导航网格
            if (systemSettings.asyncBuild)
            {
                NavMeshBuilder.UpdateNavMeshDataAsync(
                    navMeshData,
                    buildSettings,
                    buildSources,
                    bounds
                );
            }
            else
            {
                navMeshData = NavMeshBuilder.BuildNavMeshData(
                    buildSettings,
                    buildSources,
                    bounds,
                    Vector3.zero,
                    Quaternion.identity
                );
                
                NavMesh.AddNavMeshData(navMeshData);
            }
        }
        
        private Bounds CalculateSceneBounds()
        {
            // 计算包含所有导航源的边界
            Bounds bounds = new Bounds();
            bool hasBounds = false;
            
            foreach (NavMeshBuildSource source in buildSources)
            {
                Bounds sourceBounds = CalculateSourceBounds(source);
                
                if (!hasBounds)
                {
                    bounds = sourceBounds;
                    hasBounds = true;
                }
                else
                {
                    bounds.Encapsulate(sourceBounds);
                }
            }
            
            // 如果没有找到边界,使用默认值
            if (!hasBounds)
            {
                bounds = new Bounds(Vector3.zero, new Vector3(100, 100, 100));
            }
            
            // 扩大边界以确保完全包含
            bounds.Expand(10.0f);
            
            return bounds;
        }
        
        private Bounds CalculateSourceBounds(NavMeshBuildSource source)
        {
            switch (source.shape)
            {
                case NavMeshBuildSourceShape.Mesh:
                    Mesh mesh = source.sourceObject as Mesh;
                    if (mesh != null)
                    {
                        Bounds meshBounds = mesh.bounds;
                        // 转换到世界空间
                        Vector3 min = source.transform.MultiplyPoint(meshBounds.min);
                        Vector3 max = source.transform.MultiplyPoint(meshBounds.max);
                        return new Bounds((min + max) * 0.5f, max - min);
                    }
                    break;
                    
                case NavMeshBuildSourceShape.Terrain:
                    TerrainData terrain = source.sourceObject as TerrainData;
                    if (terrain != null)
                    {
                        Bounds terrainBounds = terrain.bounds;
                        Vector3 min = source.transform.MultiplyPoint(terrainBounds.min);
                        Vector3 max = source.transform.MultiplyPoint(terrainBounds.max);
                        return new Bounds((min + max) * 0.5f, max - min);
                    }
                    break;
                    
                case NavMeshBuildSourceShape.Box:
                case NavMeshBuildSourceShape.Sphere:
                case NavMeshBuildSourceShape.Capsule:
                case NavMeshBuildSourceShape.ModifierBox:
                    // 对于基本形状,使用转换后的局部边界
                    Matrix4x4 matrix = source.transform;
                    Vector3 center = matrix.GetColumn(3);
                    Vector3 size = matrix.lossyScale;
                    return new Bounds(center, size);
            }
            
            return new Bounds(Vector3.zero, Vector3.zero);
        }
        
        private void OnDestroy()
        {
            // 清理导航网格数据
            if (navMeshData != null)
            {
                NavMesh.RemoveNavMeshData(navMeshData);
            }
        }
    }
    
    // 导航系统设置数据类
    [CreateAssetMenu(fileName = "NavigationSystemSettings", menuName = "AI/Navigation System Settings")]
    public class NavigationSystemSettings : ScriptableObject
    {
        [Header("常规设置")]
        public int defaultAgentTypeID = 0;
        public bool buildHeightMesh = true;
        public bool autoRebuild = true;
        public float rebuildInterval = 0.5f;
        public bool asyncBuild = true;
        
        [Header("默认代理参数")]
        public float defaultAgentRadius = 0.5f;
        public float defaultAgentHeight = 2.0f;
        public float defaultAgentStepHeight = 0.4f;
        public float defaultMaxSlope = 45.0f;
        
        [Header("性能设置")]
        public int pathfindingIterationsPerFrame = 100;
        public float avoidancePredictionTime = 2.0f;
        public int maxNavMeshNodes = 1024;
        
        [Header("高级设置")]
        public float cellSize = 0.1666667f;
        public float cellHeight = 0.1f;
        public float maxEdgeLength = 12.0f;
        public float maxEdgeError = 1.0f;
        public float detailSampleDistance = 6.0f;
        public float detailSampleMaxError = 1.0f;
    }
    
    // 导航源标签组件
    public class NavMeshSourceTag : MonoBehaviour
    {
        [Header("源设置")]
        public int areaType = 0; // 0=可行走,1=不可行走,2=跳跃,3=爬梯等
        public bool includeInNavMesh = true;
        public bool isWalkable = true;
        
        [Header("几何体设置")]
        public Mesh sourceMesh;
        public NavMeshBuildSourceShape shape = NavMeshBuildSourceShape.Mesh;
        public Vector3 modifierSize = Vector3.one;
        
        public List<NavMeshBuildSource> Collect()
        {
            List<NavMeshBuildSource> sources = new List<NavMeshBuildSource>();
            
            if (!includeInNavMesh)
            {
                return sources;
            }
            
            NavMeshBuildSource source = new NavMeshBuildSource();
            source.area = areaType;
            
            // 根据形状类型设置源
            switch (shape)
            {
                case NavMeshBuildSourceShape.Mesh:
                    if (sourceMesh != null)
                    {
                        source.shape = NavMeshBuildSourceShape.Mesh;
                        source.sourceObject = sourceMesh;
                        source.transform = transform.localToWorldMatrix;
                        sources.Add(source);
                    }
                    break;
                    
                case NavMeshBuildSourceShape.Box:
                    source.shape = NavMeshBuildSourceShape.Box;
                    source.size = modifierSize;
                    source.transform = transform.localToWorldMatrix;
                    sources.Add(source);
                    break;
                    
                case NavMeshBuildSourceShape.Sphere:
                    source.shape = NavMeshBuildSourceShape.Sphere;
                    source.size = Vector3.one * modifierSize.x;
                    source.transform = transform.localToWorldMatrix;
                    sources.Add(source);
                    break;
                    
                case NavMeshBuildSourceShape.Capsule:
                    source.shape = NavMeshBuildSourceShape.Capsule;
                    source.size = new Vector3(modifierSize.x, modifierSize.y, 0);
                    source.transform = transform.localToWorldMatrix;
                    sources.Add(source);
                    break;
            }
            
            return sources;
        }
        
        private void OnDrawGizmosSelected()
        {
            // 在编辑器中选择时显示导航源范围
            Gizmos.color = isWalkable ? Color.green : Color.red;
            
            switch (shape)
            {
                case NavMeshBuildSourceShape.Mesh:
                    if (sourceMesh != null)
                    {
                        Gizmos.matrix = transform.localToWorldMatrix;
                        Gizmos.DrawWireMesh(sourceMesh);
                    }
                    break;
                    
                case NavMeshBuildSourceShape.Box:
                    Gizmos.matrix = transform.localToWorldMatrix;
                    Gizmos.DrawWireCube(Vector3.zero, modifierSize);
                    break;
                    
                case NavMeshBuildSourceShape.Sphere:
                    Gizmos.matrix = transform.localToWorldMatrix;
                    Gizmos.DrawWireSphere(Vector3.zero, modifierSize.x);
                    break;
                    
                case NavMeshBuildSourceShape.Capsule:
                    Gizmos.matrix = transform.localToWorldMatrix;
                    DrawWireCapsule(Vector3.zero, modifierSize.x, modifierSize.y);
                    break;
            }
        }
        
        private void DrawWireCapsule(Vector3 center, float radius, float height)
        {
            // 绘制胶囊体线框
            Vector3 up = Vector3.up * (height - radius * 2) * 0.5f;
            
            // 绘制中间圆柱部分
            Gizmos.DrawWireSphere(center + up, radius);
            Gizmos.DrawWireSphere(center - up, radius);
            
            // 绘制侧面线
            for (int i = 0; i < 360; i += 45)
            {
                float angle = i * Mathf.Deg2Rad;
                Vector3 point = new Vector3(Mathf.Cos(angle) * radius, 0, Mathf.Sin(angle) * radius);
                Gizmos.DrawLine(center + up + point, center - up + point);
            }
        }
    }
}

5.2.2 开发环境优化配置

在商业项目中,导航网格系统的性能至关重要。以下是一些优化配置建议:

  1. 分层构建策略:根据地形复杂度使用不同的体素大小
  2. 异步处理:避免在主线程执行耗时的导航计算
  3. 内存管理:合理管理导航网格数据的生命周期
  4. 调试工具:开发可视化调试工具,便于问题排查
// 导航系统性能优化管理器
public class NavigationPerformanceOptimizer : MonoBehaviour
{
    [System.Serializable]
    public class OptimizationProfile
    {
        public string profileName;
        public float rebuildInterval = 1.0f;
        public int maxSimultaneousPathfinds = 10;
        public bool useSimplifiedPathfinding = false;
        public float pathSimplificationTolerance = 0.5f;
        public bool cachePaths = true;
        public int maxCachedPaths = 100;
    }
    
    public OptimizationProfile[] profiles;
    public string currentProfileName = "Default";
    
    private Dictionary<string, OptimizationProfile> profileLookup;
    private Queue<NavMeshPath> pathCache;
    private int activePathfinds = 0;
    
    private void Start()
    {
        InitializeProfiles();
        InitializePathCache();
        ApplyProfile(currentProfileName);
    }
    
    private void InitializeProfiles()
    {
        profileLookup = new Dictionary<string, OptimizationProfile>();
        
        // 创建默认配置文件
        if (profiles.Length == 0)
        {
            profiles = new OptimizationProfile[]
            {
                new OptimizationProfile
                {
                    profileName = "Default",
                    rebuildInterval = 1.0f,
                    maxSimultaneousPathfinds = 10
                },
                new OptimizationProfile
                {
                    profileName = "Performance",
                    rebuildInterval = 2.0f,
                    maxSimultaneousPathfinds = 5,
                    useSimplifiedPathfinding = true,
                    pathSimplificationTolerance = 1.0f
                },
                new OptimizationProfile
                {
                    profileName = "Quality",
                    rebuildInterval = 0.5f,
                    maxSimultaneousPathfinds = 20,
                    useSimplifiedPathfinding = false
                }
            };
        }
        
        foreach (OptimizationProfile profile in profiles)
        {
            profileLookup[profile.profileName] = profile;
        }
    }
    
    private void InitializePathCache()
    {
        pathCache = new Queue<NavMeshPath>();
        
        // 预创建路径对象,减少GC
        for (int i = 0; i < 20; i++)
        {
            pathCache.Enqueue(new NavMeshPath());
        }
    }
    
    public void ApplyProfile(string profileName)
    {
        if (profileLookup.ContainsKey(profileName))
        {
            OptimizationProfile profile = profileLookup[profileName];
            currentProfileName = profileName;
            
            // 应用性能设置
            NavMesh.pathfindingIterationsPerFrame = profile.maxSimultaneousPathfinds * 10;
            
            Debug.Log($"应用导航性能配置: {profileName}");
        }
    }
    
    public NavMeshPath GetCachedPath()
    {
        if (pathCache.Count > 0)
        {
            return pathCache.Dequeue();
        }
        
        // 缓存为空时创建新路径
        return new NavMeshPath();
    }
    
    public void ReturnPathToCache(NavMeshPath path)
    {
        if (pathCache.Count < 100) // 限制缓存大小
        {
            path.ClearCorners();
            pathCache.Enqueue(path);
        }
    }
    
    public bool CanStartPathfind()
    {
        if (profileLookup.ContainsKey(currentProfileName))
        {
            OptimizationProfile profile = profileLookup[currentProfileName];
            return activePathfinds < profile.maxSimultaneousPathfinds;
        }
        
        return true;
    }
    
    public void StartPathfind()
    {
        activePathfinds++;
    }
    
    public void EndPathfind()
    {
        activePathfinds = Mathf.Max(0, activePathfinds - 1);
    }
    
    // 简化的路径查找方法
    public NavMeshPath FindSimplifiedPath(Vector3 source, Vector3 target)
    {
        if (!CanStartPathfind())
        {
            return null;
        }
        
        StartPathfind();
        
        NavMeshPath path = GetCachedPath();
        
        try
        {
            if (NavMesh.CalculatePath(source, target, NavMesh.AllAreas, path))
            {
                if (profileLookup[currentProfileName].useSimplifiedPathfinding)
                {
                    path = SimplifyPath(path);
                }
            }
        }
        finally
        {
            EndPathfind();
        }
        
        return path;
    }
    
    private NavMeshPath SimplifyPath(NavMeshPath originalPath)
    {
        if (originalPath.corners.Length <= 2)
        {
            return originalPath;
        }
        
        List<Vector3> simplified = new List<Vector3>();
        simplified.Add(originalPath.corners[0]);
        
        float tolerance = profileLookup[currentProfileName].pathSimplificationTolerance;
        
        for (int i = 1; i < originalPath.corners.Length - 1; i++)
        {
            Vector3 lastAdded = simplified[simplified.Count - 1];
            Vector3 current = originalPath.corners[i];
            Vector3 next = originalPath.corners[i + 1];
            
            // 检查当前点是否可以跳过
            Vector3 lineDir = (next - lastAdded).normalized;
            float distance = Vector3.Cross(lineDir, current - lastAdded).magnitude;
            
            if (distance > tolerance)
            {
                simplified.Add(current);
            }
        }
        
        simplified.Add(originalPath.corners[originalPath.corners.Length - 1]);
        
        NavMeshPath simplifiedPath = GetCachedPath();
        simplifiedPath.corners = simplified.ToArray();
        
        return simplifiedPath;
    }
}

5.3 多类型代理的导航网格构建与管理

在实际游戏项目中,不同AI角色通常具有不同的移动特性。人类角色、动物、车辆、飞行器等都需要不同的导航参数。Unity的导航网格系统支持为不同类型的代理创建独立的导航数据。

5.3.1 多代理类型配置与管理

using UnityEngine;
using UnityEngine.AI;
using System.Collections.Generic;

namespace MultiAgentNavigation
{
    // 代理类型定义
    public enum AgentCategory
    {
        Humanoid,
        Vehicle,
        Animal,
        Flying,
        Swarm
    }
    
    // 代理类型配置
    [System.Serializable]
    public class AgentTypeConfiguration
    {
        public string typeName;
        public AgentCategory category;
        public int agentTypeID;
        
        [Header("物理参数")]
        public float radius = 0.5f;
        public float height = 2.0f;
        public float stepHeight = 0.4f;
        public float maxSlope = 45.0f;
        
        [Header("移动参数")]
        public float speed = 3.5f;
        public float angularSpeed = 120f;
        public float acceleration = 8f;
        public float stoppingDistance = 0.5f;
        
        [Header("避障参数")]
        public float avoidanceRadius = 1.0f;
        public float avoidancePriority = 50f;
        public LayerMask avoidanceMask = -1;
        
        [Header("高级设置")]
        public bool autoTraverseOffMeshLink = true;
        public bool autoRepath = true;
        public float autoRepathDistance = 1.0f;
    }
    
    // 多代理导航管理器
    public class MultiAgentNavigationManager : MonoBehaviour
    {
        [Header("代理类型配置")]
        public List<AgentTypeConfiguration> agentConfigurations;
        
        [Header("导航网格设置")]
        public bool buildSeparateNavMeshes = true;
        public float navMeshBuildMargin = 5.0f;
        
        private Dictionary<int, AgentTypeConfiguration> configurationLookup;
        private Dictionary<int, NavMeshData> navMeshDataMap;
        private Dictionary<int, NavMeshBuildSettings> buildSettingsMap;
        
        private void Awake()
        {
            InitializeAgentConfigurations();
            InitializeNavMeshData();
            
            if (buildSeparateNavMeshes)
            {
                BuildMultiAgentNavMeshes();
            }
        }
        
        private void InitializeAgentConfigurations()
        {
            configurationLookup = new Dictionary<int, AgentTypeConfiguration>();
            
            // 确保至少有一个默认配置
            if (agentConfigurations == null || agentConfigurations.Count == 0)
            {
                CreateDefaultConfigurations();
            }
            
            // 建立查找表
            foreach (AgentTypeConfiguration config in agentConfigurations)
            {
                configurationLookup[config.agentTypeID] = config;
                
                // 确保代理类型ID在Unity中注册
                RegisterAgentType(config);
            }
        }
        
        private void CreateDefaultConfigurations()
        {
            agentConfigurations = new List<AgentTypeConfiguration>();
            
            // 人类代理
            agentConfigurations.Add(new AgentTypeConfiguration
            {
                typeName = "Human",
                category = AgentCategory.Humanoid,
                agentTypeID = 0,
                radius = 0.5f,
                height = 2.0f,
                stepHeight = 0.4f,
                maxSlope = 45.0f,
                speed = 3.5f
            });
            
            // 车辆代理
            agentConfigurations.Add(new AgentTypeConfiguration
            {
                typeName = "Vehicle",
                category = AgentCategory.Vehicle,
                agentTypeID = 1,
                radius = 1.0f,
                height = 2.5f,
                stepHeight = 0.6f,
                maxSlope = 30.0f,
                speed = 8.0f
            });
            
            // 动物代理
            agentConfigurations.Add(new AgentTypeConfiguration
            {
                typeName = "Animal",
                category = AgentCategory.Animal,
                agentTypeID = 2,
                radius = 0.3f,
                height = 1.0f,
                stepHeight = 0.3f,
                maxSlope = 60.0f,
                speed = 5.0f
            });
            
            // 飞行代理
            agentConfigurations.Add(new AgentTypeConfiguration
            {
                typeName = "Flying",
                category = AgentCategory.Flying,
                agentTypeID = 3,
                radius = 0.2f,
                height = 0.5f,
                stepHeight = 0.1f,
                maxSlope = 90.0f,
                speed = 7.0f
            });
        }
        
        private void RegisterAgentType(AgentTypeConfiguration config)
        {
            // 创建或获取代理类型的构建设置
            NavMeshBuildSettings settings = NavMesh.CreateSettings();
            settings.agentTypeID = config.agentTypeID;
            settings.agentRadius = config.radius;
            settings.agentHeight = config.height;
            settings.agentSlope = config.maxSlope;
            settings.agentClimb = config.stepHeight;
            
            // 添加到导航系统
            NavMesh.AddSettings(settings);
            
            if (buildSettingsMap == null)
            {
                buildSettingsMap = new Dictionary<int, NavMeshBuildSettings>();
            }
            
            buildSettingsMap[config.agentTypeID] = settings;
        }
        
        private void InitializeNavMeshData()
        {
            navMeshDataMap = new Dictionary<int, NavMeshData>();
        }
        
        private void BuildMultiAgentNavMeshes()
        {
            // 为每个代理类型构建独立的导航网格
            foreach (AgentTypeConfiguration config in agentConfigurations)
            {
                BuildNavMeshForAgentType(config.agentTypeID);
            }
        }
        
        private void BuildNavMeshForAgentType(int agentTypeID)
        {
            if (!configurationLookup.ContainsKey(agentTypeID))
            {
                Debug.LogWarning($"未找到代理类型ID {agentTypeID} 的配置");
                return;
            }
            
            if (!buildSettingsMap.ContainsKey(agentTypeID))
            {
                Debug.LogWarning($"未找到代理类型ID {agentTypeID} 的构建设置");
                return;
            }
            
            // 收集适合该代理类型的导航源
            List<NavMeshBuildSource> sources = CollectSourcesForAgentType(agentTypeID);
            
            if (sources.Count == 0)
            {
                Debug.LogWarning($"没有找到适合代理类型 {agentTypeID} 的导航源");
                return;
            }
            
            // 计算边界
            Bounds bounds = CalculateBoundsForSources(sources);
            bounds.Expand(navMeshBuildMargin);
            
            // 构建导航网格数据
            NavMeshBuildSettings settings = buildSettingsMap[agentTypeID];
            NavMeshData navMeshData = NavMeshBuilder.BuildNavMeshData(
                settings,
                sources,
                bounds,
                Vector3.zero,
                Quaternion.identity
            );
            
            if (navMeshData != null)
            {
                // 移除旧的导航网格数据(如果存在)
                if (navMeshDataMap.ContainsKey(agentTypeID) && navMeshDataMap[agentTypeID] != null)
                {
                    NavMesh.RemoveNavMeshData(navMeshDataMap[agentTypeID]);
                }
                
                // 添加新的导航网格数据
                NavMesh.AddNavMeshData(navMeshData);
                navMeshDataMap[agentTypeID] = navMeshData;
                
                Debug.Log($"为代理类型 {configurationLookup[agentTypeID].typeName} 构建导航网格完成");
            }
        }
        
        private List<NavMeshBuildSource> CollectSourcesForAgentType(int agentTypeID)
        {
            List<NavMeshBuildSource> filteredSources = new List<NavMeshBuildSource>();
            
            // 收集所有导航源
            NavMeshSourceTag[] allTags = FindObjectsOfType<NavMeshSourceTag>();
            
            foreach (NavMeshSourceTag tag in allTags)
            {
                // 根据代理类型过滤源
                if (IsSourceSuitableForAgent(tag, agentTypeID))
                {
                    filteredSources.AddRange(tag.Collect());
                }
            }
            
            return filteredSources;
        }
        
        private bool IsSourceSuitableForAgent(NavMeshSourceTag source, int agentTypeID)
        {
            if (!configurationLookup.ContainsKey(agentTypeID))
            {
                return false;
            }
            
            AgentTypeConfiguration config = configurationLookup[agentTypeID];
            
            // 根据代理类别和源属性进行过滤
            switch (config.category)
            {
                case AgentCategory.Humanoid:
                    // 人类可以行走在大部分表面上
                    return source.areaType == 0 && source.isWalkable;
                    
                case AgentCategory.Vehicle:
                    // 车辆需要平坦的道路
                    return source.areaType == 0 && source.isWalkable;
                    
                case AgentCategory.Animal:
                    // 动物可以行走在更多类型的地形上
                    return source.areaType <= 2 && source.isWalkable;
                    
                case AgentCategory.Flying:
                    // 飞行器可以穿越大部分区域,除了固体障碍物
                    return source.areaType != 1; // 不是不可行走区域
                    
                case AgentCategory.Swarm:
                    // 群体可以穿越非常小的空间
                    return true;
                    
                default:
                    return source.areaType == 0;
            }
        }
        
        private Bounds CalculateBoundsForSources(List<NavMeshBuildSource> sources)
        {
            Bounds bounds = new Bounds();
            bool hasBounds = false;
            
            foreach (NavMeshBuildSource source in sources)
            {
                Bounds sourceBounds = CalculateSourceBounds(source);
                
                if (!hasBounds)
                {
                    bounds = sourceBounds;
                    hasBounds = true;
                }
                else
                {
                    bounds.Encapsulate(sourceBounds);
                }
            }
            
            if (!hasBounds)
            {
                bounds = new Bounds(Vector3.zero, new Vector3(100, 100, 100));
            }
            
            return bounds;
        }
        
        private Bounds CalculateSourceBounds(NavMeshBuildSource source)
        {
            // 与之前相同的边界计算方法
            // 这里简化为使用转换后的位置
            Vector3 position = source.transform.GetColumn(3);
            Vector3 size = Vector3.one;
            
            if (source.shape == NavMeshBuildSourceShape.Mesh)
            {
                Mesh mesh = source.sourceObject as Mesh;
                if (mesh != null)
                {
                    size = mesh.bounds.size;
                }
            }
            
            return new Bounds(position, size);
        }
        
        public AgentTypeConfiguration GetAgentConfiguration(int agentTypeID)
        {
            if (configurationLookup.ContainsKey(agentTypeID))
            {
                return configurationLookup[agentTypeID];
            }
            
            return null;
        }
        
        public NavMeshAgent CreateAgentForType(int agentTypeID, GameObject agentObject)
        {
            AgentTypeConfiguration config = GetAgentConfiguration(agentTypeID);
            
            if (config == null)
            {
                Debug.LogError($"无法创建代理:未找到类型ID {agentTypeID} 的配置");
                return null;
            }
            
            // 添加NavMeshAgent组件
            NavMeshAgent agent = agentObject.AddComponent<NavMeshAgent>();
            
            // 配置代理参数
            agent.agentTypeID = config.agentTypeID;
            agent.radius = config.radius;
            agent.height = config.height;
            agent.speed = config.speed;
            agent.angularSpeed = config.angularSpeed;
            agent.acceleration = config.acceleration;
            agent.stoppingDistance = config.stoppingDistance;
            agent.autoTraverseOffMeshLink = config.autoTraverseOffMeshLink;
            agent.autoRepath = config.autoRepath;
            
            // 配置避障
            agent.obstacleAvoidanceType = ObstacleAvoidanceType.GoodQualityObstacleAvoidance;
            agent.avoidancePriority = Mathf.RoundToInt(config.avoidancePriority);
            
            return agent;
        }
        
        public bool IsPositionReachable(Vector3 position, int agentTypeID, float maxDistance = 1.0f)
        {
            NavMeshHit hit;
            return NavMesh.SamplePosition(
                position, 
                out hit, 
                maxDistance, 
                NavMesh.AllAreas
            );
        }
        
        public Vector3 FindNearestReachablePoint(Vector3 position, int agentTypeID, float maxDistance = 10.0f)
        {
            NavMeshHit hit;
            if (NavMesh.SamplePosition(position, out hit, maxDistance, NavMesh.AllAreas))
            {
                return hit.position;
            }
            
            return position;
        }
        
        public void UpdateNavMeshForAgentType(int agentTypeID)
        {
            if (buildSeparateNavMeshes)
            {
                BuildNavMeshForAgentType(agentTypeID);
            }
            else
            {
                Debug.LogWarning("单独代理类型的导航网格更新需要启用 buildSeparateNavMeshes");
            }
        }
        
        private void OnDestroy()
        {
            // 清理所有导航网格数据
            foreach (KeyValuePair<int, NavMeshData> entry in navMeshDataMap)
            {
                if (entry.Value != null)
                {
                    NavMesh.RemoveNavMeshData(entry.Value);
                }
            }
        }
    }
    
    // 智能代理控制器
    public class IntelligentAgentController : MonoBehaviour
    {
        [Header("代理设置")]
        public int agentTypeID = 0;
        public bool autoConfigure = true;
        
        [Header("移动行为")]
        public float wanderRadius = 10f;
        public float minWanderDelay = 2f;
        public float maxWanderDelay = 5f;
        
        private NavMeshAgent navAgent;
        private MultiAgentNavigationManager navigationManager;
        private Vector3 currentDestination;
        private float wanderTimer;
        private float nextWanderTime;
        
        private void Start()
        {
            InitializeAgent();
            
            if (autoConfigure)
            {
                StartWandering();
            }
        }
        
        private void InitializeAgent()
        {
            // 查找导航管理器
            navigationManager = FindObjectOfType<MultiAgentNavigationManager>();
            
            if (navigationManager == null)
            {
                Debug.LogError("未找到 MultiAgentNavigationManager");
                return;
            }
            
            // 创建并配置代理
            navAgent = navigationManager.CreateAgentForType(agentTypeID, gameObject);
            
            if (navAgent == null)
            {
                Debug.LogError("无法创建 NavMeshAgent");
                return;
            }
            
            // 设置初始位置为可到达点
            Vector3 reachablePosition = navigationManager.FindNearestReachablePoint(
                transform.position, 
                agentTypeID
            );
            
            transform.position = reachablePosition;
            navAgent.Warp(reachablePosition);
            
            Debug.Log($"智能代理初始化完成,类型ID: {agentTypeID}");
        }
        
        private void Update()
        {
            if (navAgent == null || !autoConfigure)
            {
                return;
            }
            
            // 更新漫游计时器
            wanderTimer += Time.deltaTime;
            
            if (wanderTimer >= nextWanderTime)
            {
                FindNewWanderDestination();
                wanderTimer = 0f;
                nextWanderTime = Random.Range(minWanderDelay, maxWanderDelay);
            }
            
            // 检查是否到达目的地
            if (!navAgent.pathPending && navAgent.remainingDistance <= navAgent.stoppingDistance)
            {
                if (!navAgent.hasPath || navAgent.velocity.sqrMagnitude == 0f)
                {
                    // 到达目的地,重置计时器
                    wanderTimer = nextWanderTime - 0.1f;
                }
            }
        }
        
        private void StartWandering()
        {
            wanderTimer = 0f;
            nextWanderTime = Random.Range(minWanderDelay, maxWanderDelay);
            FindNewWanderDestination();
        }
        
        private void FindNewWanderDestination()
        {
            Vector3 randomDirection = Random.insideUnitSphere * wanderRadius;
            randomDirection.y = 0; // 保持水平移动
            
            Vector3 targetPosition = transform.position + randomDirection;
            
            // 确保目标位置可到达
            targetPosition = navigationManager.FindNearestReachablePoint(targetPosition, agentTypeID, wanderRadius);
            
            SetDestination(targetPosition);
        }
        
        public void SetDestination(Vector3 destination)
        {
            if (navAgent != null && navAgent.isActiveAndEnabled)
            {
                currentDestination = destination;
                navAgent.SetDestination(destination);
            }
        }
        
        public void StopMovement()
        {
            if (navAgent != null)
            {
                navAgent.isStopped = true;
            }
        }
        
        public void ResumeMovement()
        {
            if (navAgent != null)
            {
                navAgent.isStopped = false;
            }
        }
        
        public bool HasReachedDestination()
        {
            if (navAgent == null)
            {
                return true;
            }
            
            return !navAgent.pathPending && 
                   navAgent.remainingDistance <= navAgent.stoppingDistance && 
                   (!navAgent.hasPath || navAgent.velocity.sqrMagnitude == 0f);
        }
        
        public NavMeshPath CalculatePathTo(Vector3 target)
        {
            if (navAgent == null || navigationManager == null)
            {
                return null;
            }
            
            return navigationManager.FindSimplifiedPath(transform.position, target);
        }
        
        private void OnDrawGizmosSelected()
        {
            // 绘制代理的可视化信息
            if (navAgent != null)
            {
                // 绘制代理半径
                Gizmos.color = Color.blue;
                Gizmos.DrawWireSphere(transform.position, navAgent.radius);
                
                // 绘制当前路径
                if (navAgent.hasPath)
                {
                    Gizmos.color = Color.green;
                    Vector3[] corners = navAgent.path.corners;
                    
                    for (int i = 0; i < corners.Length - 1; i++)
                    {
                        Gizmos.DrawLine(corners[i], corners[i + 1]);
                        Gizmos.DrawSphere(corners[i], 0.1f);
                    }
                    
                    Gizmos.DrawSphere(corners[corners.Length - 1], 0.1f);
                }
                
                // 绘制目标位置
                if (currentDestination != Vector3.zero)
                {
                    Gizmos.color = Color.red;
                    Gizmos.DrawSphere(currentDestination, 0.2f);
                    Gizmos.DrawLine(transform.position, currentDestination);
                }
            }
        }
    }
}

5.3.2 代理群体管理与优化

在包含大量AI角色的游戏中,有效的群体管理至关重要。以下实现展示了如何优化多个代理的导航性能:

// 代理群体管理器
public class AgentCrowdManager : MonoBehaviour
{
    [System.Serializable]
    public class CrowdFormation
    {
        public string formationName;
        public FormationType type;
        public Vector3[] relativePositions;
        public float spacing = 2.0f;
    }
    
    public enum FormationType
    {
        Line,
        Column,
        Wedge,
        Vee,
        Square,
        Circle
    }
    
    [Header("群体设置")]
    public int maxAgents = 50;
    public float updateInterval = 0.1f;
    public bool useFormations = true;
    
    [Header("编队配置")]
    public List<CrowdFormation> formations;
    
    private List<IntelligentAgentController> activeAgents;
    private Dictionary<int, CrowdFormation> formationLookup;
    private float updateTimer;
    
    private void Start()
    {
        InitializeFormations();
        activeAgents = new List<IntelligentAgentController>();
        updateTimer = 0f;
    }
    
    private void InitializeFormations()
    {
        formationLookup = new Dictionary<int, CrowdFormation>();
        
        // 创建默认编队
        if (formations == null || formations.Count == 0)
        {
            CreateDefaultFormations();
        }
        
        for (int i = 0; i < formations.Count; i++)
        {
            formationLookup[i] = formations[i];
        }
    }
    
    private void CreateDefaultFormations()
    {
        formations = new List<CrowdFormation>();
        
        // 线性编队
        formations.Add(new CrowdFormation
        {
            formationName = "Line",
            type = FormationType.Line,
            spacing = 2.0f,
            relativePositions = CalculateLineFormation(5)
        });
        
        // 楔形编队
        formations.Add(new CrowdFormation
        {
            formationName = "Wedge",
            type = FormationType.Wedge,
            spacing = 2.5f,
            relativePositions = CalculateWedgeFormation(5)
        });
        
        // 圆形编队
        formations.Add(new CrowdFormation
        {
            formationName = "Circle",
            type = FormationType.Circle,
            spacing = 3.0f,
            relativePositions = CalculateCircleFormation(8)
        });
    }
    
    private Vector3[] CalculateLineFormation(int agentCount)
    {
        Vector3[] positions = new Vector3[agentCount];
        
        for (int i = 0; i < agentCount; i++)
        {
            positions[i] = new Vector3(i * 2.0f, 0, 0);
        }
        
        return positions;
    }
    
    private Vector3[] CalculateWedgeFormation(int agentCount)
    {
        List<Vector3> positions = new List<Vector3>();
        
        int rows = Mathf.CeilToInt(Mathf.Sqrt(agentCount));
        
        for (int row = 0; row < rows; row++)
        {
            int agentsInRow = row + 1;
            float rowOffset = row * 2.5f;
            
            for (int col = 0; col < agentsInRow; col++)
            {
                float colOffset = (col - row * 0.5f) * 2.5f;
                positions.Add(new Vector3(colOffset, 0, -rowOffset));
            }
        }
        
        return positions.ToArray();
    }
    
    private Vector3[] CalculateCircleFormation(int agentCount)
    {
        Vector3[] positions = new Vector3[agentCount];
        float radius = 5.0f;
        
        for (int i = 0; i < agentCount; i++)
        {
            float angle = i * (360f / agentCount) * Mathf.Deg2Rad;
            positions[i] = new Vector3(
                Mathf.Cos(angle) * radius,
                0,
                Mathf.Sin(angle) * radius
            );
        }
        
        return positions;
    }
    
    private void Update()
    {
        updateTimer += Time.deltaTime;
        
        if (updateTimer >= updateInterval)
        {
            UpdateCrowdNavigation();
            updateTimer = 0f;
        }
    }
    
    private void UpdateCrowdNavigation()
    {
        if (activeAgents.Count == 0)
        {
            return;
        }
        
        // 分批更新代理,避免在同一帧更新所有代理
        int batchSize = Mathf.CeilToInt(activeAgents.Count * 0.1f); // 每次更新10%
        int startIndex = (Time.frameCount % 10) * batchSize;
        
        for (int i = 0; i < batchSize && startIndex + i < activeAgents.Count; i++)
        {
            IntelligentAgentController agent = activeAgents[startIndex + i];
            
            if (agent != null && agent.enabled)
            {
                UpdateAgentInCrowd(agent);
            }
        }
    }
    
    private void UpdateAgentInCrowd(IntelligentAgentController agent)
    {
        // 实现群体行为逻辑
        if (useFormations && activeAgents.Count > 1)
        {
            ApplyFormationBehavior(agent);
        }
        else
        {
            ApplyIndividualBehavior(agent);
        }
    }
    
    private void ApplyFormationBehavior(IntelligentAgentController agent)
    {
        // 根据代理在群体中的位置应用编队行为
        int agentIndex = activeAgents.IndexOf(agent);
        
        if (agentIndex >= 0)
        {
            // 选择编队(基于群体大小)
            int formationIndex = Mathf.Min(agentIndex / 5, formations.Count - 1);
            
            if (formationLookup.ContainsKey(formationIndex))
            {
                CrowdFormation formation = formationLookup[formationIndex];
                
                // 计算编队中的目标位置
                Vector3 formationTarget = CalculateFormationPosition(agentIndex, formation);
                
                // 设置目标
                agent.SetDestination(formationTarget);
            }
        }
    }
    
    private Vector3 CalculateFormationPosition(int agentIndex, CrowdFormation formation)
    {
        // 计算编队中心(使用第一个代理的位置或指定目标)
        Vector3 formationCenter = Vector3.zero;
        
        if (activeAgents.Count > 0 && activeAgents[0] != null)
        {
            formationCenter = activeAgents[0].transform.position;
        }
        
        // 获取相对位置
        int positionIndex = agentIndex % formation.relativePositions.Length;
        Vector3 relativePosition = formation.relativePositions[positionIndex];
        
        // 应用编队旋转
        Quaternion formationRotation = CalculateFormationRotation();
        Vector3 worldPosition = formationCenter + formationRotation * relativePosition;
        
        return worldPosition;
    }
    
    private Quaternion CalculateFormationRotation()
    {
        // 基于第一个代理的朝向或群体平均朝向计算编队旋转
        if (activeAgents.Count > 0 && activeAgents[0] != null)
        {
            return activeAgents[0].transform.rotation;
        }
        
        return Quaternion.identity;
    }
    
    private void ApplyIndividualBehavior(IntelligentAgentController agent)
    {
        // 个体行为逻辑
        // 可以在这里实现避免碰撞、保持距离等行为
    }
    
    public void RegisterAgent(IntelligentAgentController agent)
    {
        if (!activeAgents.Contains(agent) && activeAgents.Count < maxAgents)
        {
            activeAgents.Add(agent);
            
            // 禁用自动漫游,由群体管理器控制
            if (agent.autoConfigure)
            {
                agent.autoConfigure = false;
            }
        }
    }
    
    public void UnregisterAgent(IntelligentAgentController agent)
    {
        if (activeAgents.Contains(agent))
        {
            activeAgents.Remove(agent);
        }
    }
    
    public void MoveFormationTo(Vector3 destination, int formationIndex = 0)
    {
        if (formationIndex < 0 || formationIndex >= formations.Count)
        {
            Debug.LogWarning($"编队索引 {formationIndex} 无效");
            return;
        }
        
        // 将整个编队移动到目标位置
        CrowdFormation formation = formations[formationIndex];
        
        for (int i = 0; i < Mathf.Min(activeAgents.Count, formation.relativePositions.Length); i++)
        {
            IntelligentAgentController agent = activeAgents[i];
            
            if (agent != null)
            {
                Vector3 relativePosition = formation.relativePositions[i];
                Vector3 targetPosition = destination + relativePosition;
                
                agent.SetDestination(targetPosition);
            }
        }
    }
    
    public void SetFormation(int formationIndex)
    {
        if (formationIndex >= 0 && formationIndex < formations.Count)
        {
            // 更新所有代理的编队位置
            for (int i = 0; i < activeAgents.Count; i++)
            {
                if (i < formations[formationIndex].relativePositions.Length)
                {
                    // 编队位置将在下一帧更新
                }
            }
        }
    }
    
    private void OnDrawGizmos()
    {
        // 绘制群体信息
        if (activeAgents != null && activeAgents.Count > 0)
        {
            Gizmos.color = Color.yellow;
            
            // 绘制代理之间的连接线
            for (int i = 0; i < activeAgents.Count - 1; i++)
            {
                if (activeAgents[i] != null && activeAgents[i + 1] != null)
                {
                    Gizmos.DrawLine(
                        activeAgents[i].transform.position,
                        activeAgents[i + 1].transform.position
                    );
                }
            }
            
            // 绘制群体边界
            Bounds crowdBounds = CalculateCrowdBounds();
            Gizmos.color = new Color(1, 1, 0, 0.3f);
            Gizmos.DrawWireCube(crowdBounds.center, crowdBounds.size);
        }
    }
    
    private Bounds CalculateCrowdBounds()
    {
        Bounds bounds = new Bounds();
        bool hasBounds = false;
        
        foreach (IntelligentAgentController agent in activeAgents)
        {
            if (agent != null)
            {
                if (!hasBounds)
                {
                    bounds = new Bounds(agent.transform.position, Vector3.zero);
                    hasBounds = true;
                }
                else
                {
                    bounds.Encapsulate(agent.transform.position);
                }
            }
        }
        
        return bounds;
    }
}

5.4 运行时导航网格数据的生成与更新

动态环境是许多现代游戏的共同特征。运行时生成和更新导航网格数据对于支持可破坏环境、移动平台和玩家建造系统等功能至关重要。

5.4.1 动态导航网格生成系统

using UnityEngine;
using UnityEngine.AI;
using System.Collections.Generic;
using System.Collections;

namespace DynamicNavigation
{
    // 动态导航网格管理器
    public class DynamicNavMeshManager : MonoBehaviour
    {
        [System.Serializable]
        public class DynamicNavMeshSettings
        {
            public float updateThreshold = 1.0f; // 位置变化超过此值触发更新
            public float minUpdateInterval = 0.5f; // 最小更新间隔
            public bool incrementalUpdates = true; // 使用增量更新
            public float incrementalUpdateRadius = 5.0f; // 增量更新半径
            public int maxConcurrentUpdates = 2; // 最大并发更新数
        }
        
        [Header("动态设置")]
        public DynamicNavMeshSettings settings;
        
        [Header("调试")]
        public bool showDebugVisualization = true;
        public Color dynamicAreaColor = new Color(0, 1, 0, 0.3f);
        
        private NavMeshData navMeshData;
        private NavMeshDataInstance navMeshInstance;
        private List<NavMeshBuildSource> staticSources;
        private List<DynamicNavMeshObject> dynamicObjects;
        private Dictionary<DynamicNavMeshObject, NavMeshBuildSource> dynamicSources;
        
        private AsyncOperation currentUpdateOperation;
        private Queue<Bounds> updateQueue;
        private float lastUpdateTime;
        private bool isUpdating;
        
        private void Awake()
        {
            InitializeDynamicNavMeshSystem();
        }
        
        private void InitializeDynamicNavMeshSystem()
        {
            // 初始化数据结构
            dynamicObjects = new List<DynamicNavMeshObject>();
            dynamicSources = new Dictionary<DynamicNavMeshObject, NavMeshBuildSource>();
            updateQueue = new Queue<Bounds>();
            
            // 收集静态导航源
            CollectStaticSources();
            
            // 构建初始导航网格
            BuildInitialNavMesh();
            
            // 开始监控动态对象
            StartCoroutine(MonitorDynamicObjects());
        }
        
        private void CollectStaticSources()
        {
            staticSources = new List<NavMeshBuildSource>();
            
            // 收集所有标记为静态的导航源
            NavMeshSourceTag[] allTags = FindObjectsOfType<NavMeshSourceTag>();
            
            foreach (NavMeshSourceTag tag in allTags)
            {
                if (tag.gameObject.isStatic)
                {
                    staticSources.AddRange(tag.Collect());
                }
            }
            
            Debug.Log($"收集到 {staticSources.Count} 个静态导航源");
        }
        
        private void BuildInitialNavMesh()
        {
            // 合并静态和动态源
            List<NavMeshBuildSource> allSources = new List<NavMeshBuildSource>(staticSources);
            
            // 创建导航网格设置
            NavMeshBuildSettings buildSettings = NavMesh.CreateSettings();
            buildSettings.agentTypeID = 0;
            
            // 计算边界
            Bounds bounds = CalculateTotalBounds(allSources);
            
            // 构建导航网格数据
            navMeshData = NavMeshBuilder.BuildNavMeshData(
                buildSettings,
                allSources,
                bounds,
                Vector3.zero,
                Quaternion.identity
            );
            
            // 添加到导航系统
            navMeshInstance = NavMesh.AddNavMeshData(navMeshData);
            
            Debug.Log("初始导航网格构建完成");
        }
        
        public void RegisterDynamicObject(DynamicNavMeshObject dynamicObject)
        {
            if (!dynamicObjects.Contains(dynamicObject))
            {
                dynamicObjects.Add(dynamicObject);
                
                // 监听对象的变化
                dynamicObject.OnTransformChanged += HandleDynamicObjectChanged;
                dynamicObject.OnDestroyed += HandleDynamicObjectDestroyed;
                
                // 初始添加对象到导航网格
                AddDynamicObjectToNavMesh(dynamicObject);
            }
        }
        
        public void UnregisterDynamicObject(DynamicNavMeshObject dynamicObject)
        {
            if (dynamicObjects.Contains(dynamicObject))
            {
                // 移除事件监听
                dynamicObject.OnTransformChanged -= HandleDynamicObjectChanged;
                dynamicObject.OnDestroyed -= HandleDynamicObjectDestroyed;
                
                // 从导航网格中移除对象
                RemoveDynamicObjectFromNavMesh(dynamicObject);
                
                dynamicObjects.Remove(dynamicObject);
            }
        }
        
        private void AddDynamicObjectToNavMesh(DynamicNavMeshObject dynamicObject)
        {
            // 收集对象的导航源
            List<NavMeshBuildSource> objectSources = dynamicObject.CollectNavMeshSources();
            
            if (objectSources.Count > 0)
            {
                // 存储源数据
                foreach (NavMeshBuildSource source in objectSources)
                {
                    dynamicSources[dynamicObject] = source;
                }
                
                // 触发导航网格更新
                RequestNavMeshUpdateAroundObject(dynamicObject);
            }
        }
        
        private void RemoveDynamicObjectFromNavMesh(DynamicNavMeshObject dynamicObject)
        {
            if (dynamicSources.ContainsKey(dynamicObject))
            {
                dynamicSources.Remove(dynamicObject);
                
                // 触发导航网格更新
                RequestNavMeshUpdateAroundObject(dynamicObject);
            }
        }
        
        private void HandleDynamicObjectChanged(DynamicNavMeshObject changedObject, Vector3 positionDelta)
        {
            // 检查是否超过更新阈值
            if (positionDelta.magnitude > settings.updateThreshold)
            {
                RequestNavMeshUpdateAroundObject(changedObject);
            }
        }
        
        private void HandleDynamicObjectDestroyed(DynamicNavMeshObject destroyedObject)
        {
            UnregisterDynamicObject(destroyedObject);
        }
        
        private void RequestNavMeshUpdateAroundObject(DynamicNavMeshObject dynamicObject)
        {
            // 计算需要更新的区域边界
            Bounds updateBounds = CalculateObjectBounds(dynamicObject);
            updateBounds.Expand(settings.incrementalUpdateRadius);
            
            // 添加到更新队列
            updateQueue.Enqueue(updateBounds);
            
            // 尝试开始更新
            TryStartNavMeshUpdate();
        }
        
        private void RequestFullNavMeshUpdate()
        {
            // 请求完全更新
            Bounds fullBounds = CalculateTotalBounds(GetAllSources());
            updateQueue.Enqueue(fullBounds);
            
            TryStartNavMeshUpdate();
        }
        
        private void TryStartNavMeshUpdate()
        {
            if (!isUpdating && updateQueue.Count > 0 && 
                Time.time - lastUpdateTime > settings.minUpdateInterval)
            {
                StartCoroutine(ProcessNavMeshUpdate());
            }
        }
        
        private IEnumerator ProcessNavMeshUpdate()
        {
            isUpdating = true;
            
            while (updateQueue.Count > 0)
            {
                Bounds updateBounds = updateQueue.Dequeue();
                
                // 检查是否应该使用增量更新
                if (settings.incrementalUpdates && navMeshData != null)
                {
                    yield return StartCoroutine(UpdateNavMeshIncrementally(updateBounds));
                }
                else
                {
                    yield return StartCoroutine(RebuildFullNavMesh());
                }
                
                lastUpdateTime = Time.time;
                
                // 限制并发更新数量
                if (updateQueue.Count > 0 && settings.maxConcurrentUpdates > 1)
                {
                    yield return new WaitForSeconds(0.1f);
                }
            }
            
            isUpdating = false;
        }
        
        private IEnumerator UpdateNavMeshIncrementally(Bounds updateBounds)
        {
            // 收集更新区域内的所有源
            List<NavMeshBuildSource> sourcesInBounds = CollectSourcesInBounds(updateBounds);
            
            if (sourcesInBounds.Count == 0)
            {
                yield break;
            }
            
            // 创建增量更新设置
            NavMeshBuildSettings buildSettings = NavMesh.CreateSettings();
            buildSettings.agentTypeID = 0;
            
            // 异步更新导航网格
            AsyncOperation updateOperation = NavMeshBuilder.UpdateNavMeshDataAsync(
                navMeshData,
                buildSettings,
                sourcesInBounds,
                updateBounds
            );
            
            currentUpdateOperation = updateOperation;
            
            // 等待更新完成
            while (!updateOperation.isDone)
            {
                yield return null;
            }
            
            currentUpdateOperation = null;
            
            Debug.Log($"增量导航网格更新完成,更新了 {sourcesInBounds.Count} 个源");
        }
        
        private IEnumerator RebuildFullNavMesh()
        {
            // 收集所有源
            List<NavMeshBuildSource> allSources = GetAllSources();
            
            if (allSources.Count == 0)
            {
                yield break;
            }
            
            // 创建新的导航网格数据
            NavMeshBuildSettings buildSettings = NavMesh.CreateSettings();
            buildSettings.agentTypeID = 0;
            
            Bounds totalBounds = CalculateTotalBounds(allSources);
            
            NavMeshData newNavMeshData = NavMeshBuilder.BuildNavMeshData(
                buildSettings,
                allSources,
                totalBounds,
                Vector3.zero,
                Quaternion.identity
            );
            
            // 等待一帧以确保安全
            yield return null;
            
            // 替换旧的导航网格数据
            if (navMeshInstance.valid)
            {
                NavMesh.RemoveNavMeshData(navMeshInstance);
            }
            
            navMeshData = newNavMeshData;
            navMeshInstance = NavMesh.AddNavMeshData(navMeshData);
            
            Debug.Log($"完全导航网格重建完成,包含 {allSources.Count} 个源");
        }
        
        private List<NavMeshBuildSource> GetAllSources()
        {
            List<NavMeshBuildSource> allSources = new List<NavMeshBuildSource>(staticSources);
            
            // 添加所有动态源
            foreach (NavMeshBuildSource source in dynamicSources.Values)
            {
                allSources.Add(source);
            }
            
            return allSources;
        }
        
        private List<NavMeshBuildSource> CollectSourcesInBounds(Bounds bounds)
        {
            List<NavMeshBuildSource> sourcesInBounds = new List<NavMeshBuildSource>();
            
            // 添加边界内的静态源
            foreach (NavMeshBuildSource source in staticSources)
            {
                if (bounds.Intersects(CalculateSourceBounds(source)))
                {
                    sourcesInBounds.Add(source);
                }
            }
            
            // 添加边界内的动态源
            foreach (KeyValuePair<DynamicNavMeshObject, NavMeshBuildSource> entry in dynamicSources)
            {
                if (bounds.Intersects(CalculateSourceBounds(entry.Value)))
                {
                    sourcesInBounds.Add(entry.Value);
                }
            }
            
            return sourcesInBounds;
        }
        
        private Bounds CalculateObjectBounds(DynamicNavMeshObject dynamicObject)
        {
            // 计算动态对象的边界
            Renderer renderer = dynamicObject.GetComponent<Renderer>();
            if (renderer != null)
            {
                return renderer.bounds;
            }
            
            Collider collider = dynamicObject.GetComponent<Collider>();
            if (collider != null)
            {
                return collider.bounds;
            }
            
            // 默认边界
            return new Bounds(dynamicObject.transform.position, Vector3.one * 2f);
        }
        
        private Bounds CalculateSourceBounds(NavMeshBuildSource source)
        {
            // 简化版的边界计算
            Vector3 position = source.transform.GetColumn(3);
            return new Bounds(position, Vector3.one);
        }
        
        private Bounds CalculateTotalBounds(List<NavMeshBuildSource> sources)
        {
            Bounds totalBounds = new Bounds();
            bool hasBounds = false;
            
            foreach (NavMeshBuildSource source in sources)
            {
                Bounds sourceBounds = CalculateSourceBounds(source);
                
                if (!hasBounds)
                {
                    totalBounds = sourceBounds;
                    hasBounds = true;
                }
                else
                {
                    totalBounds.Encapsulate(sourceBounds);
                }
            }
            
            if (!hasBounds)
            {
                totalBounds = new Bounds(Vector3.zero, new Vector3(100, 100, 100));
            }
            
            return totalBounds;
        }
        
        private IEnumerator MonitorDynamicObjects()
        {
            while (true)
            {
                yield return new WaitForSeconds(1.0f);
                
                // 定期检查动态对象的状态
                CheckDynamicObjectsValidity();
            }
        }
        
        private void CheckDynamicObjectsValidity()
        {
            // 移除无效的动态对象
            List<DynamicNavMeshObject> invalidObjects = new List<DynamicNavMeshObject>();
            
            foreach (DynamicNavMeshObject dynamicObject in dynamicObjects)
            {
                if (dynamicObject == null || !dynamicObject.gameObject.activeInHierarchy)
                {
                    invalidObjects.Add(dynamicObject);
                }
            }
            
            foreach (DynamicNavMeshObject invalidObject in invalidObjects)
            {
                UnregisterDynamicObject(invalidObject);
            }
        }
        
        private void OnDestroy()
        {
            // 清理导航网格数据
            if (navMeshInstance.valid)
            {
                NavMesh.RemoveNavMeshData(navMeshInstance);
            }
            
            // 移除所有事件监听
            foreach (DynamicNavMeshObject dynamicObject in dynamicObjects)
            {
                if (dynamicObject != null)
                {
                    dynamicObject.OnTransformChanged -= HandleDynamicObjectChanged;
                    dynamicObject.OnDestroyed -= HandleDynamicObjectDestroyed;
                }
            }
        }
        
        private void OnDrawGizmos()
        {
            if (!showDebugVisualization)
            {
                return;
            }
            
            // 绘制动态对象区域
            Gizmos.color = dynamicAreaColor;
            
            foreach (DynamicNavMeshObject dynamicObject in dynamicObjects)
            {
                if (dynamicObject != null)
                {
                    Bounds bounds = CalculateObjectBounds(dynamicObject);
                    bounds.Expand(settings.incrementalUpdateRadius);
                    
                    Gizmos.DrawWireCube(bounds.center, bounds.size);
                }
            }
            
            // 绘制更新队列
            if (updateQueue != null && updateQueue.Count > 0)
            {
                Gizmos.color = Color.red;
                
                foreach (Bounds bounds in updateQueue)
                {
                    Gizmos.DrawWireCube(bounds.center, bounds.size);
                }
            }
        }
    }
    
    // 动态导航网格对象接口
    public interface IDynamicNavMeshObject
    {
        event System.Action<DynamicNavMeshObject, Vector3> OnTransformChanged;
        event System.Action<DynamicNavMeshObject> OnDestroyed;
        
        List<NavMeshBuildSource> CollectNavMeshSources();
        void NotifyTransformChanged(Vector3 positionDelta);
    }
    
    // 动态导航网格对象基类
    public abstract class DynamicNavMeshObject : MonoBehaviour, IDynamicNavMeshObject
    {
        public event System.Action<DynamicNavMeshObject, Vector3> OnTransformChanged;
        public event System.Action<DynamicNavMeshObject> OnDestroyed;
        
        [Header("导航设置")]
        public int areaType = 0;
        public bool isWalkable = true;
        public bool affectsNavigation = true;
        
        protected Vector3 lastPosition;
        protected Quaternion lastRotation;
        protected Vector3 lastScale;
        
        protected DynamicNavMeshManager navMeshManager;
        
        protected virtual void Start()
        {
            // 缓存初始变换
            lastPosition = transform.position;
            lastRotation = transform.rotation;
            lastScale = transform.localScale;
            
            // 查找并注册到导航网格管理器
            navMeshManager = FindObjectOfType<DynamicNavMeshManager>();
            if (navMeshManager != null && affectsNavigation)
            {
                navMeshManager.RegisterDynamicObject(this);
            }
        }
        
        protected virtual void Update()
        {
            if (!affectsNavigation)
            {
                return;
            }
            
            // 检查变换是否发生变化
            Vector3 positionDelta = transform.position - lastPosition;
            Quaternion rotationDelta = transform.rotation * Quaternion.Inverse(lastRotation);
            Vector3 scaleDelta = transform.localScale - lastScale;
            
            bool hasChanged = positionDelta.sqrMagnitude > 0.0001f || 
                             rotationDelta.eulerAngles.sqrMagnitude > 0.1f || 
                             scaleDelta.sqrMagnitude > 0.0001f;
            
            if (hasChanged)
            {
                // 通知变换变化
                NotifyTransformChanged(positionDelta);
                
                // 更新缓存
                lastPosition = transform.position;
                lastRotation = transform.rotation;
                lastScale = transform.localScale;
            }
        }
        
        protected virtual void OnDestroy()
        {
            // 通知对象被销毁
            OnDestroyed?.Invoke(this);
        }
        
        public abstract List<NavMeshBuildSource> CollectNavMeshSources();
        
        public void NotifyTransformChanged(Vector3 positionDelta)
        {
            OnTransformChanged?.Invoke(this, positionDelta);
        }
    }
    
    // 动态网格对象实现
    public class DynamicMeshObject : DynamicNavMeshObject
    {
        [Header("网格设置")]
        public Mesh sourceMesh;
        public NavMeshBuildSourceShape shape = NavMeshBuildSourceShape.Mesh;
        
        public override List<NavMeshBuildSource> CollectNavMeshSources()
        {
            List<NavMeshBuildSource> sources = new List<NavMeshBuildSource>();
            
            if (!affectsNavigation || sourceMesh == null)
            {
                return sources;
            }
            
            NavMeshBuildSource source = new NavMeshBuildSource
            {
                shape = shape,
                sourceObject = sourceMesh,
                transform = transform.localToWorldMatrix,
                area = areaType
            };
            
            sources.Add(source);
            return sources;
        }
        
        protected override void OnDrawGizmosSelected()
        {
            if (!showDebugVisualization)
            {
                return;
            }
            
            // 绘制动态对象的边界
            Gizmos.color = isWalkable ? Color.green : Color.yellow;
            Gizmos.matrix = transform.localToWorldMatrix;
            
            if (sourceMesh != null)
            {
                Gizmos.DrawWireMesh(sourceMesh);
            }
            else
            {
                // 绘制默认立方体
                Gizmos.DrawWireCube(Vector3.zero, Vector3.one);
            }
        }
    }
    
    // 动态障碍物对象
    public class DynamicObstacle : DynamicNavMeshObject
    {
        [Header("障碍物设置")]
        public ObstacleShape obstacleShape = ObstacleShape.Box;
        public Vector3 obstacleSize = Vector3.one;
        public bool isCarving = true; // 是否从导航网格中挖空
        
        public enum ObstacleShape
        {
            Box,
            Sphere,
            Capsule
        }
        
        private NavMeshObstacle navMeshObstacle;
        
        protected override void Start()
        {
            base.Start();
            
            // 添加NavMeshObstacle组件
            if (isCarving)
            {
                navMeshObstacle = gameObject.AddComponent<NavMeshObstacle>();
                ConfigureNavMeshObstacle();
            }
        }
        
        private void ConfigureNavMeshObstacle()
        {
            if (navMeshObstacle == null)
            {
                return;
            }
            
            // 配置障碍物形状
            switch (obstacleShape)
            {
                case ObstacleShape.Box:
                    navMeshObstacle.shape = NavMeshObstacleShape.Box;
                    navMeshObstacle.size = obstacleSize;
                    break;
                    
                case ObstacleShape.Sphere:
                    navMeshObstacle.shape = NavMeshObstacleShape.Sphere;
                    navMeshObstacle.radius = obstacleSize.x;
                    break;
                    
                case ObstacleShape.Capsule:
                    navMeshObstacle.shape = NavMeshObstacleShape.Capsule;
                    navMeshObstacle.radius = obstacleSize.x;
                    navMeshObstacle.height = obstacleSize.y;
                    break;
            }
            
            navMeshObstacle.carving = isCarving;
            navMeshObstacle.carveOnlyStationary = false;
        }
        
        public override List<NavMeshBuildSource> CollectNavMeshSources()
        {
            List<NavMeshBuildSource> sources = new List<NavMeshBuildSource>();
            
            if (!affectsNavigation || isCarving)
            {
                // 如果使用NavMeshObstacle挖空,则不作为构建源
                return sources;
            }
            
            // 作为不可行走区域添加到导航网格
            NavMeshBuildSource source = new NavMeshBuildSource();
            source.area = 1; // 不可行走区域
            
            switch (obstacleShape)
            {
                case ObstacleShape.Box:
                    source.shape = NavMeshBuildSourceShape.Box;
                    source.size = obstacleSize;
                    break;
                    
                case ObstacleShape.Sphere:
                    source.shape = NavMeshBuildSourceShape.Sphere;
                    source.size = Vector3.one * obstacleSize.x;
                    break;
                    
                case ObstacleShape.Capsule:
                    source.shape = NavMeshBuildSourceShape.Capsule;
                    source.size = new Vector3(obstacleSize.x, obstacleSize.y, 0);
                    break;
            }
            
            source.transform = transform.localToWorldMatrix;
            sources.Add(source);
            
            return sources;
        }
        
        protected override void Update()
        {
            base.Update();
            
            // 更新NavMeshObstacle位置
            if (navMeshObstacle != null)
            {
                navMeshObstacle.transform.position = transform.position;
                navMeshObstacle.transform.rotation = transform.rotation;
            }
        }
        
        public void SetCarving(bool carving)
        {
            isCarving = carving;
            
            if (navMeshObstacle != null)
            {
                navMeshObstacle.carving = carving;
            }
        }
        
        protected override void OnDrawGizmosSelected()
        {
            if (!showDebugVisualization)
            {
                return;
            }
            
            // 绘制障碍物
            Gizmos.color = isCarving ? Color.red : new Color(1, 0.5f, 0, 1);
            Gizmos.matrix = transform.localToWorldMatrix;
            
            switch (obstacleShape)
            {
                case ObstacleShape.Box:
                    Gizmos.DrawWireCube(Vector3.zero, obstacleSize);
                    break;
                    
                case ObstacleShape.Sphere:
                    Gizmos.DrawWireSphere(Vector3.zero, obstacleSize.x);
                    break;
                    
                case ObstacleShape.Capsule:
                    DrawWireCapsule(Vector3.zero, obstacleSize.x, obstacleSize.y);
                    break;
            }
        }
        
        private void DrawWireCapsule(Vector3 center, float radius, float height)
        {
            // 绘制胶囊体线框
            Vector3 up = Vector3.up * (height - radius * 2) * 0.5f;
            
            // 绘制半球
            for (int i = 0; i < 180; i += 30)
            {
                float angle1 = i * Mathf.Deg2Rad;
                float angle2 = (i + 30) * Mathf.Deg2Rad;
                
                Vector3 point1 = new Vector3(Mathf.Cos(angle1) * radius, up.y, Mathf.Sin(angle1) * radius);
                Vector3 point2 = new Vector3(Mathf.Cos(angle2) * radius, up.y, Mathf.Sin(angle2) * radius);
                
                Gizmos.DrawLine(center + up + point1, center + up + point2);
                Gizmos.DrawLine(center - up + point1, center - up + point2);
            }
            
            // 绘制侧面线
            for (int i = 0; i < 360; i += 45)
            {
                float angle = i * Mathf.Deg2Rad;
                Vector3 point = new Vector3(Mathf.Cos(angle) * radius, 0, Mathf.Sin(angle) * radius);
                Gizmos.DrawLine(center + up + point, center - up + point);
            }
        }
    }
}

5.4.2 性能优化与内存管理

动态导航网格更新可能对性能产生显著影响。以下是优化策略的实现:

// 动态导航网格性能优化器
public class DynamicNavMeshOptimizer : MonoBehaviour
{
    [System.Serializable]
    public class OptimizationSettings
    {
        public bool useLOD = true;
        public float[] lodDistances = { 10f, 20f, 50f };
        public float[] lodUpdateIntervals = { 0.5f, 1.0f, 2.0f };
        
        public bool batchUpdates = true;
        public int maxBatchSize = 5;
        public float batchDelay = 0.1f;
        
        public bool prioritizePlayerArea = true;
        public float playerAreaRadius = 15f;
        public float playerAreaUpdateInterval = 0.2f;
        
        public bool useObjectPooling = true;
        public int navMeshDataPoolSize = 10;
    }
    
    public OptimizationSettings settings;
    
    private DynamicNavMeshManager navMeshManager;
    private Transform playerTransform;
    private Dictionary<DynamicNavMeshObject, int> objectLODLevels;
    private Queue<Bounds> updateBatch;
    private Coroutine batchUpdateCoroutine;
    
    private class NavMeshDataPool
    {
        private Queue<NavMeshData> pool;
        private int maxSize;
        
        public NavMeshDataPool(int maxSize)
        {
            this.maxSize = maxSize;
            pool = new Queue<NavMeshData>();
        }
        
        public NavMeshData Get()
        {
            if (pool.Count > 0)
            {
                return pool.Dequeue();
            }
            
            return null;
        }
        
        public void Return(NavMeshData data)
        {
            if (pool.Count < maxSize && data != null)
            {
                pool.Enqueue(data);
            }
        }
        
        public void Clear()
        {
            foreach (NavMeshData data in pool)
            {
                // 清理导航网格数据
                if (data != null)
                {
                    // 注意:NavMeshData没有明确的Dispose方法
                    // 实际项目中可能需要自定义清理逻辑
                }
            }
            
            pool.Clear();
        }
    }
    
    private NavMeshDataPool navMeshDataPool;
    
    private void Start()
    {
        navMeshManager = FindObjectOfType<DynamicNavMeshManager>();
        playerTransform = FindPlayerTransform();
        
        objectLODLevels = new Dictionary<DynamicNavMeshObject, int>();
        updateBatch = new Queue<Bounds>();
        
        if (settings.useObjectPooling)
        {
            navMeshDataPool = new NavMeshDataPool(settings.navMeshDataPoolSize);
        }
        
        // 开始LOD更新协程
        if (settings.useLOD)
        {
            StartCoroutine(UpdateLODLevels());
        }
        
        // 开始玩家区域优先更新协程
        if (settings.prioritizePlayerArea)
        {
            StartCoroutine(UpdatePlayerArea());
        }
    }
    
    private Transform FindPlayerTransform()
    {
        // 查找玩家对象(根据项目结构调整)
        GameObject player = GameObject.FindGameObjectWithTag("Player");
        if (player != null)
        {
            return player.transform;
        }
        
        // 如果没有找到,使用主相机的位置
        if (Camera.main != null)
        {
            return Camera.main.transform;
        }
        
        return null;
    }
    
    private IEnumerator UpdateLODLevels()
    {
        while (true)
        {
            yield return new WaitForSeconds(1.0f);
            
            UpdateAllObjectLODLevels();
        }
    }
    
    private void UpdateAllObjectLODLevels()
    {
        if (playerTransform == null || !settings.useLOD)
        {
            return;
        }
        
        // 更新所有动态对象的LOD级别
        // 注意:这里需要访问DynamicNavMeshManager的动态对象列表
        // 实际实现中可能需要修改DynamicNavMeshManager以提供访问接口
    }
    
    private int CalculateLODLevelForObject(Vector3 objectPosition)
    {
        if (playerTransform == null)
        {
            return 0;
        }
        
        float distance = Vector3.Distance(objectPosition, playerTransform.position);
        
        for (int i = 0; i < settings.lodDistances.Length; i++)
        {
            if (distance <= settings.lodDistances[i])
            {
                return i;
            }
        }
        
        return settings.lodDistances.Length;
    }
    
    private IEnumerator UpdatePlayerArea()
    {
        while (true)
        {
            yield return new WaitForSeconds(settings.playerAreaUpdateInterval);
            
            if (playerTransform != null && settings.prioritizePlayerArea)
            {
                UpdateNavMeshAroundPlayer();
            }
        }
    }
    
    private void UpdateNavMeshAroundPlayer()
    {
        if (playerTransform == null || navMeshManager == null)
        {
            return;
        }
        
        // 创建玩家周围的更新区域
        Bounds playerBounds = new Bounds(
            playerTransform.position,
            Vector3.one * settings.playerAreaRadius * 2
        );
        
        // 请求更新
        RequestNavMeshUpdate(playerBounds, true);
    }
    
    public void RequestNavMeshUpdate(Bounds bounds, bool isPriority = false)
    {
        if (navMeshManager == null)
        {
            return;
        }
        
        if (settings.batchUpdates && !isPriority)
        {
            // 添加到批处理队列
            updateBatch.Enqueue(bounds);
            
            if (batchUpdateCoroutine == null)
            {
                batchUpdateCoroutine = StartCoroutine(ProcessBatchUpdates());
            }
        }
        else
        {
            // 立即处理优先级更新
            // 这里需要调用DynamicNavMeshManager的更新方法
            // navMeshManager.RequestUpdateInBounds(bounds);
        }
    }
    
    private IEnumerator ProcessBatchUpdates()
    {
        while (updateBatch.Count > 0)
        {
            // 收集一批更新
            List<Bounds> batch = new List<Bounds>();
            for (int i = 0; i < settings.maxBatchSize && updateBatch.Count > 0; i++)
            {
                batch.Add(updateBatch.Dequeue());
            }
            
            // 合并边界
            Bounds mergedBounds = MergeBounds(batch);
            
            // 执行更新
            // navMeshManager.RequestUpdateInBounds(mergedBounds);
            
            // 等待批处理延迟
            yield return new WaitForSeconds(settings.batchDelay);
        }
        
        batchUpdateCoroutine = null;
    }
    
    private Bounds MergeBounds(List<Bounds> boundsList)
    {
        if (boundsList.Count == 0)
        {
            return new Bounds(Vector3.zero, Vector3.zero);
        }
        
        Bounds merged = boundsList[0];
        
        for (int i = 1; i < boundsList.Count; i++)
        {
            merged.Encapsulate(boundsList[i]);
        }
        
        return merged;
    }
    
    public NavMeshData GetNavMeshDataFromPool()
    {
        if (settings.useObjectPooling && navMeshDataPool != null)
        {
            return navMeshDataPool.Get();
        }
        
        return null;
    }
    
    public void ReturnNavMeshDataToPool(NavMeshData data)
    {
        if (settings.useObjectPooling && navMeshDataPool != null)
        {
            navMeshDataPool.Return(data);
        }
    }
    
    private void OnDestroy()
    {
        // 清理对象池
        if (navMeshDataPool != null)
        {
            navMeshDataPool.Clear();
        }
        
        // 停止所有协程
        if (batchUpdateCoroutine != null)
        {
            StopCoroutine(batchUpdateCoroutine);
        }
    }
}

5.5 导航网格实例的生命周期控制

在复杂的游戏场景中,可能需要管理多个导航网格实例,每个实例对应不同的区域或代理类型。有效的生命周期管理确保内存使用高效且不会产生泄漏。

5.5.1 导航网格实例管理器

using UnityEngine;
using UnityEngine.AI;
using System.Collections.Generic;

namespace NavMeshLifecycle
{
    // 导航网格实例信息
    [System.Serializable]
    public class NavMeshInstanceInfo
    {
        public string instanceId;
        public NavMeshData navMeshData;
        public NavMeshDataInstance navMeshInstance;
        public Bounds bounds;
        public int agentTypeID;
        public bool isActive;
        public float lastUsedTime;
        
        // 使用统计
        public int queryCount;
        public float averageQueryTime;
        
        public NavMeshInstanceInfo(string id, NavMeshData data, Bounds bounds, int agentTypeID)
        {
            this.instanceId = id;
            this.navMeshData = data;
            this.bounds = bounds;
            this.agentTypeID = agentTypeID;
            this.isActive = false;
            this.lastUsedTime = Time.time;
            this.queryCount = 0;
            this.averageQueryTime = 0f;
        }
        
        public void RecordQuery(float queryTime)
        {
            queryCount++;
            averageQueryTime = (averageQueryTime * (queryCount - 1) + queryTime) / queryCount;
            lastUsedTime = Time.time;
        }
        
        public float CalculatePriority(float currentTime)
        {
            // 优先级计算:基于使用频率和最近使用时间
            float timeSinceLastUse = currentTime - lastUsedTime;
            float usagePriority = Mathf.Clamp01(1.0f - timeSinceLastUse / 300f); // 5分钟衰减
            float queryPriority = Mathf.Clamp01(queryCount / 100f);
            
            return (usagePriority * 0.7f + queryPriority * 0.3f);
        }
    }
    
    // 导航网格实例管理器
    public class NavMeshInstanceManager : MonoBehaviour
    {
        [System.Serializable]
        public class LifecycleSettings
        {
            public int maxInstances = 10;
            public float unusedInstanceTimeout = 300f; // 5分钟
            public bool autoRemoveUnused = true;
            public float cleanupInterval = 60f; // 每60秒清理一次
            public bool logLifecycleEvents = true;
        }
        
        [Header("生命周期设置")]
        public LifecycleSettings settings;
        
        [Header("性能优化")]
        public bool useBackgroundLoading = true;
        public float backgroundLoadBudget = 0.01f; // 每帧最多花费10ms
        
        private Dictionary<string, NavMeshInstanceInfo> instances;
        private Queue<NavMeshBuildRequest> buildQueue;
        private float lastCleanupTime;
        
        private class NavMeshBuildRequest
        {
            public string instanceId;
            public List<NavMeshBuildSource> sources;
            public Bounds bounds;
            public int agentTypeID;
            public System.Action<NavMeshInstanceInfo> callback;
        }
        
        private void Awake()
        {
            InitializeManager();
        }
        
        private void InitializeManager()
        {
            instances = new Dictionary<string, NavMeshInstanceInfo>();
            buildQueue = new Queue<NavMeshBuildRequest>();
            lastCleanupTime = Time.time;
            
            // 开始后台处理协程
            if (useBackgroundLoading)
            {
                StartCoroutine(ProcessBackgroundBuilds());
            }
            
            // 开始清理协程
            if (settings.autoRemoveUnused)
            {
                StartCoroutine(AutoCleanupRoutine());
            }
        }
        
        public string CreateNavMeshInstance(
            List<NavMeshBuildSource> sources, 
            Bounds bounds, 
            int agentTypeID,
            bool buildImmediately = true)
        {
            // 生成唯一ID
            string instanceId = GenerateInstanceId(bounds, agentTypeID);
            
            // 检查是否已存在相同实例
            if (instances.ContainsKey(instanceId))
            {
                NavMeshInstanceInfo existing = instances[instanceId];
                existing.lastUsedTime = Time.time;
                
                if (settings.logLifecycleEvents)
                {
                    Debug.Log($"重用现有导航网格实例: {instanceId}");
                }
                
                return instanceId;
            }
            
            // 检查实例数量限制
            if (instances.Count >= settings.maxInstances)
            {
                RemoveLowestPriorityInstance();
            }
            
            if (buildImmediately)
            {
                // 立即构建
                NavMeshInstanceInfo instanceInfo = BuildNavMeshInstance(
                    instanceId, 
                    sources, 
                    bounds, 
                    agentTypeID
                );
                
                instances[instanceId] = instanceInfo;
                return instanceId;
            }
            else
            {
                // 加入构建队列
                NavMeshBuildRequest request = new NavMeshBuildRequest
                {
                    instanceId = instanceId,
                    sources = sources,
                    bounds = bounds,
                    agentTypeID = agentTypeID
                };
                
                buildQueue.Enqueue(request);
                return instanceId;
            }
        }
        
        public void CreateNavMeshInstanceAsync(
            List<NavMeshBuildSource> sources,
            Bounds bounds,
            int agentTypeID,
            System.Action<NavMeshInstanceInfo> callback)
        {
            string instanceId = GenerateInstanceId(bounds, agentTypeID);
            
            if (instances.ContainsKey(instanceId))
            {
                callback?.Invoke(instances[instanceId]);
                return;
            }
            
            NavMeshBuildRequest request = new NavMeshBuildRequest
            {
                instanceId = instanceId,
                sources = sources,
                bounds = bounds,
                agentTypeID = agentTypeID,
                callback = callback
            };
            
            buildQueue.Enqueue(request);
        }
        
        private NavMeshInstanceInfo BuildNavMeshInstance(
            string instanceId,
            List<NavMeshBuildSource> sources,
            Bounds bounds,
            int agentTypeID)
        {
            System.Diagnostics.Stopwatch stopwatch = System.Diagnostics.Stopwatch.StartNew();
            
            // 创建导航网格设置
            NavMeshBuildSettings buildSettings = NavMesh.CreateSettings();
            buildSettings.agentTypeID = agentTypeID;
            
            // 构建导航网格数据
            NavMeshData navMeshData = NavMeshBuilder.BuildNavMeshData(
                buildSettings,
                sources,
                bounds,
                Vector3.zero,
                Quaternion.identity
            );
            
            // 创建导航网格实例
            NavMeshDataInstance navMeshInstance = NavMesh.AddNavMeshData(navMeshData);
            
            stopwatch.Stop();
            
            if (settings.logLifecycleEvents)
            {
                Debug.Log($"构建导航网格实例 {instanceId} 完成,耗时: {stopwatch.ElapsedMilliseconds}ms");
            }
            
            // 创建实例信息
            NavMeshInstanceInfo instanceInfo = new NavMeshInstanceInfo(
                instanceId, 
                navMeshData, 
                bounds, 
                agentTypeID
            );
            
            instanceInfo.navMeshInstance = navMeshInstance;
            instanceInfo.isActive = true;
            
            return instanceInfo;
        }
        
        private System.Collections.IEnumerator ProcessBackgroundBuilds()
        {
            while (true)
            {
                if (buildQueue.Count > 0)
                {
                    System.Diagnostics.Stopwatch frameTimer = System.Diagnostics.Stopwatch.StartNew();
                    
                    while (buildQueue.Count > 0 && 
                           frameTimer.Elapsed.TotalMilliseconds < backgroundLoadBudget)
                    {
                        NavMeshBuildRequest request = buildQueue.Dequeue();
                        
                        // 检查实例数量限制
                        if (instances.Count >= settings.maxInstances)
                        {
                            RemoveLowestPriorityInstance();
                        }
                        
                        // 构建实例
                        NavMeshInstanceInfo instanceInfo = BuildNavMeshInstance(
                            request.instanceId,
                            request.sources,
                            request.bounds,
                            request.agentTypeID
                        );
                        
                        instances[request.instanceId] = instanceInfo;
                        
                        // 调用回调
                        request.callback?.Invoke(instanceInfo);
                    }
                }
                
                yield return null;
            }
        }
        
        private string GenerateInstanceId(Bounds bounds, int agentTypeID)
        {
            // 基于边界和代理类型生成唯一ID
            Vector3 center = bounds.center;
            Vector3 size = bounds.size;
            
            return $"NavMesh_{agentTypeID}_{center.x:F1}_{center.y:F1}_{center.z:F1}_{size.x:F1}_{size.y:F1}_{size.z:F1}";
        }
        
        public bool ActivateInstance(string instanceId)
        {
            if (instances.ContainsKey(instanceId))
            {
                NavMeshInstanceInfo instance = instances[instanceId];
                
                if (!instance.isActive)
                {
                    instance.navMeshInstance = NavMesh.AddNavMeshData(instance.navMeshData);
                    instance.isActive = true;
                    
                    if (settings.logLifecycleEvents)
                    {
                        Debug.Log($"激活导航网格实例: {instanceId}");
                    }
                }
                
                instance.lastUsedTime = Time.time;
                return true;
            }
            
            return false;
        }
        
        public bool DeactivateInstance(string instanceId)
        {
            if (instances.ContainsKey(instanceId))
            {
                NavMeshInstanceInfo instance = instances[instanceId];
                
                if (instance.isActive)
                {
                    NavMesh.RemoveNavMeshData(instance.navMeshInstance);
                    instance.isActive = false;
                    
                    if (settings.logLifecycleEvents)
                    {
                        Debug.Log($"停用导航网格实例: {instanceId}");
                    }
                }
                
                return true;
            }
            
            return false;
        }
        
        public void RemoveInstance(string instanceId)
        {
            if (instances.ContainsKey(instanceId))
            {
                NavMeshInstanceInfo instance = instances[instanceId];
                
                if (instance.isActive)
                {
                    NavMesh.RemoveNavMeshData(instance.navMeshInstance);
                }
                
                instances.Remove(instanceId);
                
                if (settings.logLifecycleEvents)
                {
                    Debug.Log($"移除导航网格实例: {instanceId}");
                }
            }
        }
        
        private void RemoveLowestPriorityInstance()
        {
            if (instances.Count == 0)
            {
                return;
            }
            
            string lowestPriorityId = null;
            float lowestPriority = float.MaxValue;
            float currentTime = Time.time;
            
            foreach (KeyValuePair<string, NavMeshInstanceInfo> entry in instances)
            {
                float priority = entry.Value.CalculatePriority(currentTime);
                
                if (priority < lowestPriority)
                {
                    lowestPriority = priority;
                    lowestPriorityId = entry.Key;
                }
            }
            
            if (lowestPriorityId != null)
            {
                RemoveInstance(lowestPriorityId);
            }
        }
        
        private System.Collections.IEnumerator AutoCleanupRoutine()
        {
            while (true)
            {
                yield return new WaitForSeconds(settings.cleanupInterval);
                
                CleanupUnusedInstances();
            }
        }
        
        private void CleanupUnusedInstances()
        {
            float currentTime = Time.time;
            List<string> instancesToRemove = new List<string>();
            
            foreach (KeyValuePair<string, NavMeshInstanceInfo> entry in instances)
            {
                float timeSinceLastUse = currentTime - entry.Value.lastUsedTime;
                
                if (timeSinceLastUse > settings.unusedInstanceTimeout)
                {
                    instancesToRemove.Add(entry.Key);
                }
            }
            
            foreach (string instanceId in instancesToRemove)
            {
                RemoveInstance(instanceId);
            }
            
            if (settings.logLifecycleEvents && instancesToRemove.Count > 0)
            {
                Debug.Log($"清理了 {instancesToRemove.Count} 个未使用的导航网格实例");
            }
        }
        
        public NavMeshInstanceInfo GetInstanceInfo(string instanceId)
        {
            if (instances.ContainsKey(instanceId))
            {
                return instances[instanceId];
            }
            
            return null;
        }
        
        public List<string> GetAllInstanceIds()
        {
            return new List<string>(instances.Keys);
        }
        
        public void RecordQuery(string instanceId, float queryTime)
        {
            if (instances.ContainsKey(instanceId))
            {
                instances[instanceId].RecordQuery(queryTime);
            }
        }
        
        private void OnDestroy()
        {
            // 清理所有实例
            List<string> allInstanceIds = new List<string>(instances.Keys);
            
            foreach (string instanceId in allInstanceIds)
            {
                RemoveInstance(instanceId);
            }
            
            instances.Clear();
            buildQueue.Clear();
        }
        
        public void DrawDebugVisualization()
        {
            foreach (NavMeshInstanceInfo instance in instances.Values)
            {
                if (instance.isActive)
                {
                    // 绘制活动实例的边界
                    Gizmos.color = Color.green;
                }
                else
                {
                    // 绘制非活动实例的边界
                    Gizmos.color = Color.gray;
                }
                
                Gizmos.DrawWireCube(instance.bounds.center, instance.bounds.size);
                
                // 绘制实例信息
                Vector3 labelPos = instance.bounds.center + Vector3.up * instance.bounds.extents.y;
                #if UNITY_EDITOR
                UnityEditor.Handles.Label(labelPos, 
                    $"{instance.instanceId}\nQueries: {instance.queryCount}\nAvg Time: {instance.averageQueryTime:F2}ms");
                #endif
            }
        }
    }
    
    // 导航网格查询代理
    public class NavMeshQueryAgent : MonoBehaviour
    {
        [Header("查询设置")]
        public string navMeshInstanceId;
        public int agentTypeID = 0;
        public float queryTimeout = 5.0f;
        
        private NavMeshInstanceManager instanceManager;
        private NavMeshInstanceInfo currentInstance;
        private System.Diagnostics.Stopwatch queryTimer;
        
        private void Start()
        {
            instanceManager = FindObjectOfType<NavMeshInstanceManager>();
            queryTimer = new System.Diagnostics.Stopwatch();
            
            if (instanceManager == null)
            {
                Debug.LogError("未找到 NavMeshInstanceManager");
                return;
            }
            
            // 获取或创建导航网格实例
            if (string.IsNullOrEmpty(navMeshInstanceId))
            {
                // 需要根据当前位置创建或查找实例
                // 这里简化处理
            }
            else
            {
                currentInstance = instanceManager.GetInstanceInfo(navMeshInstanceId);
                
                if (currentInstance == null)
                {
                    Debug.LogWarning($"导航网格实例 {navMeshInstanceId} 不存在");
                }
            }
        }
        
        public NavMeshPath QueryPath(Vector3 start, Vector3 end)
        {
            if (currentInstance == null || !currentInstance.isActive)
            {
                Debug.LogWarning("导航网格实例不可用");
                return null;
            }
            
            queryTimer.Restart();
            
            // 执行路径查询
            NavMeshPath path = new NavMeshPath();
            bool success = NavMesh.CalculatePath(start, end, NavMesh.AllAreas, path);
            
            queryTimer.Stop();
            
            // 记录查询性能
            instanceManager.RecordQuery(navMeshInstanceId, (float)queryTimer.Elapsed.TotalMilliseconds);
            
            if (!success)
            {
                Debug.LogWarning("路径查询失败");
                return null;
            }
            
            return path;
        }
        
        public NavMeshHit QueryRaycast(Vector3 start, Vector3 direction, float maxDistance)
        {
            if (currentInstance == null || !currentInstance.isActive)
            {
                Debug.LogWarning("导航网格实例不可用");
                return new NavMeshHit();
            }
            
            queryTimer.Restart();
            
            NavMeshHit hit;
            bool success = NavMesh.Raycast(start, start + direction * maxDistance, out hit, NavMesh.AllAreas);
            
            queryTimer.Stop();
            
            instanceManager.RecordQuery(navMeshInstanceId, (float)queryTimer.Elapsed.TotalMilliseconds);
            
            if (!success)
            {
                Debug.LogWarning("射线查询失败");
            }
            
            return hit;
        }
        
        public NavMeshHit QuerySamplePosition(Vector3 position, float maxDistance)
        {
            if (currentInstance == null || !currentInstance.isActive)
            {
                Debug.LogWarning("导航网格实例不可用");
                return new NavMeshHit();
            }
            
            queryTimer.Restart();
            
            NavMeshHit hit;
            bool success = NavMesh.SamplePosition(position, out hit, maxDistance, NavMesh.AllAreas);
            
            queryTimer.Stop();
            
            instanceManager.RecordQuery(navMeshInstanceId, (float)queryTimer.Elapsed.TotalMilliseconds);
            
            if (!success)
            {
                Debug.LogWarning("位置采样失败");
            }
            
            return hit;
        }
        
        public void SwitchNavMeshInstance(string newInstanceId)
        {
            if (instanceManager == null)
            {
                return;
            }
            
            // 停用当前实例
            if (currentInstance != null && currentInstance.isActive)
            {
                instanceManager.DeactivateInstance(navMeshInstanceId);
            }
            
            // 激活新实例
            if (instanceManager.ActivateInstance(newInstanceId))
            {
                navMeshInstanceId = newInstanceId;
                currentInstance = instanceManager.GetInstanceInfo(newInstanceId);
                Debug.Log($"切换到导航网格实例: {newInstanceId}");
            }
            else
            {
                Debug.LogWarning($"无法切换到导航网格实例: {newInstanceId}");
            }
        }
    }
}

总结

Unity的导航网格系统提供了强大而灵活的工具集,能够满足从简单寻路到复杂动态环境导航的各种需求。通过合理使用多代理类型支持、动态更新机制和实例生命周期管理,开发者可以创建出既智能又高效的AI导航系统。

关键要点总结:

  1. 多代理类型支持:为不同类型的AI角色创建定制化的导航参数,确保各种角色都能在场景中自然移动。

  2. 动态导航网格更新:通过增量更新和智能批处理,实现对动态环境的实时响应,同时保持高性能。

  3. 生命周期管理:有效管理导航网格实例的创建、激活、停用和销毁,避免内存泄漏和性能问题。

  4. 性能优化:使用LOD系统、对象池和异步处理等技术,确保导航系统在各种硬件上都能流畅运行。

  5. 调试与可视化:开发强大的调试工具,帮助识别和解决导航问题,提高开发效率。

在实际商业项目中,建议根据具体需求选择合适的导航策略。对于开放世界游戏,可能需要复杂的动态更新和LOD系统;对于竞技场战斗游戏,可能更注重多代理避障和群体行为;而对于策略游戏,则可能需要高效的路径查询和批量处理。

通过深入理解和灵活应用Unity的导航网格API,开发者可以创建出能够处理复杂导航场景的AI系统,为玩家提供更加真实和沉浸式的游戏体验。

Logo

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

更多推荐