# PathBerserker2d 技术评估与使用手册 > **版本**: PathBerserker2d (Unity Asset Store) > **Unity 要求**: 2020.3+ > **依赖**: `com.unity.modules.physics2d` > **许可**: Unity Asset Store EULA > **包路径**: `Assets/PathBerserker2d/` > **官方文档**: https://oribow.github.io/PathBerserker2dDemo/Documentation/ --- ## 目录 1. [概述与设计哲学](#1-概述与设计哲学) 2. [架构总览](#2-架构总览) 3. [核心组件](#3-核心组件) 4. [NavAgent 详解](#4-navagent-详解) 5. [NavSurface 详解](#5-navsurface-详解) 6. [NavLink 与 NavLinkCluster](#6-navlink-与-navlinkcluster) 7. [辅助组件](#7-辅助组件) 8. [全局系统 — PBWorld 与 Settings](#8-全局系统--pbworld-与-settings) 9. [路径与寻路请求](#9-路径与寻路请求) 10. [预置行为脚本](#10-预置行为脚本) 11. [TransformBasedMovement 移动系统](#11-transformbasedmovement-移动系统) 12. [Demo 场景与使用模式](#12-demo-场景与使用模式) 13. [Corgi 引擎集成](#13-corgi-引擎集成) 14. [全局设置参考](#14-全局设置参考) 15. [与 BaseGames 架构集成方案](#15-与-basegames-架构集成方案) 16. [性能分析与优化建议](#16-性能分析与优化建议) 17. [优缺点总结](#17-优缺点总结) 18. [总结与建议](#18-总结与建议) --- ## 1. 概述与设计哲学 ### 1.1 什么是 PathBerserker2d PathBerserker2d 是一款专为 **2D 游戏** 设计的导航/寻路插件。与 Unity 内置的 NavMesh(面向 3D)不同,它基于 **线段(Segment)** 而非面片构建导航图,天然适合 2D 横版游戏的地形表示。 核心理念: > **从 2D Collider 自动烘焙导航线段,通过多线程 A\* 异步寻路,以事件驱动的方式委托移动实现。** ### 1.2 核心设计原则 | 原则 | 说明 | |------|------| | **线段导航** | 导航数据为沿 Collider2D 表面的线段,适合平台跳跃和横版场景 | | **自动烘焙** | 从子对象的 Collider2D 自动提取导航线段,无需手动标记 | | **异步多线程** | 寻路计算在后台线程完成(默认4线程),不阻塞主线程 | | **事件驱动** | NavAgent 通过事件通知移动组件,移动实现完全解耦 | | **动态世界** | 支持运行时烘焙、移动平台、动态链接启停 | | **链接系统** | 跳跃、下落、攀爬、电梯、传送等复杂行为通过 NavLink 建模 | ### 1.3 适用场景 - 2D 横版平台跳跃(Metroidvania / Platformer) - 2D 俯视角 RPG(360° 模式) - 需要 AI 自动寻路的 2D 游戏 - 含电梯、梯子、传送门、移动平台等复杂地形的关卡 --- ## 2. 架构总览 ### 2.1 系统架构图 ``` NavSurface (烘焙 Collider2D → 线段数据) ↓ OnEnable 时添加 PBWorld.NavGraph (全局导航图,B2DynamicTree 空间索引) ↑ NavLink / NavLinkCluster 添加连接 ↑ NavAreaMarker 标记区域 NavTag ↑ NavSegmentSubstractor 裁剪线段 NavAgent.PathTo() → PBWorld.PathTo(PathRequest) ↓ 入队 PathfinderThread (多线程 A*) → PathRequest.Fulfill(Path) ↓ 主线程轮询 NavAgent.HandlePathRequest() → 开始 FollowPath ↓ 事件驱动 TransformBasedMovement / 自定义移动 (实际移动) ↓ 完成后回调 NavAgent.CompleteSegmentTraversal() / CompleteLinkTraversal() ``` ### 2.2 关键设计模式 | 模式 | 说明 | |------|------| | **异步多线程寻路** | PathRequest 入队 → PathfinderThread 后台 A\* → 主线程轮询结果 | | **事件驱动移动** | NavAgent 触发事件,外部组件响应事件实现移动逻辑 | | **动态世界** | NavSurface 可运行时烘焙/加载/卸载,链接可动态添加/移除/切换可穿越性 | | **移动平台支持** | 所有坐标相对 NavSurface 本地坐标存储,Transform 变化时自动跟随 | | **自动重新寻路** | `autoRepathIntervall` 控制周期性重算路径,应对世界变化 | | **WebGL 兼容** | 检测平台后使用协程替代线程,确保单线程环境可用 | ### 2.3 目录结构 ``` Assets/PathBerserker2d/ ├── Scripts/PathBerserker2d/ # 核心源码 │ ├── NavAgent/ # NavAgent.cs, TransformBasedMovement.cs │ │ └── NavAgentUsers/ # 预置行为脚本 (8个) │ ├── NavSurface/ # NavSurface.cs, 碰撞体过滤, 线段创建 │ │ ├── NavSegments/ # 线段数据结构 │ │ └── Creation/ # 烘焙管线 │ ├── NavObjects/ # NavLink, NavLinkCluster, NavAreaMarker 等 │ ├── NavGraph/ # 导航图, 图节点, 空间索引 │ ├── Pathfinder/ # A* 寻路, 路径请求, 多线程 │ ├── PBWorld.cs # 全局单例管理器 │ ├── PathBerserker2dSettings.cs # 全局设置 │ └── IVelocityProvider.cs # 速度接口 ├── Demo/ # 演示场景与脚本 │ ├── Scenes/ # 15+ 场景 │ └── Scripts/ # 演示脚本 ├── Corgi/ # Corgi Engine 集成层 ├── Resources/ # 全局设置资源文件 └── Documentation/ # 官方文档 (zip) ``` --- ## 3. 核心组件 ### 3.1 组件总览 | 组件 | 菜单路径 | 职责 | |------|---------|------| | **NavSurface** | `PathBerserker2d/Nav Surface` | 从 Collider2D 烘焙导航线段 | | **NavAgent** | `PathBerserker2d/Nav Agent` | 寻路请求与路径跟随 | | **NavLink** | `PathBerserker2d/Nav Link` | 两点间导航链接(跳跃/下落/攀爬等) | | **NavLinkCluster** | `PathBerserker2d/Nav Link Cluster` | 多点互联链接集群(电梯/梯子) | | **NavAreaMarker** | `PathBerserker2d/Nav Area Marker` | 区域 NavTag 标记 | | **NavSegmentSubstractor** | — | 在烘焙时裁剪指定区域的线段 | | **DynamicObstacle** | — | 标记 GameObject 在烘焙时被忽略 | | **TransformBasedMovement** | — | 基于 Transform 的默认移动实现 | ### 3.2 组件依赖关系 ``` NavAgent ←需要→ TransformBasedMovement (或自定义移动组件) NavAgent ←依赖→ PBWorld (全局单例,自动创建) NavSurface ←依赖→ 子对象的 Collider2D NavLink / NavLinkCluster ←映射→ NavSurface 上的线段 NavAreaMarker ←需要→ RectTransform NavSegmentSubstractor ←需要→ RectTransform ``` --- ## 4. NavAgent 详解 ### 4.1 状态机 ``` NavAgent 状态: ┌─────────┐ │ Idle │ ←── 初始 / Stop() / ForceStop() / 到达目标 └────┬─────┘ │ PathTo() ▼ ┌─────────────────────────────┐ │ FollowPath │ │ ┌─────────────────────┐ │ │ │ OnSegment │ ←─ 在线段上移动 │ ├─────────────────────┤ │ │ │ WaitForLinkOnSegment│ ←─ 等待链接可用 │ ├─────────────────────┤ │ │ │ OnLink │ ←─ 正在穿越链接 │ └─────────────────────┘ │ └─────────────────────────────┘ ``` ### 4.2 公共方法 | 方法 | 返回值 | 说明 | |------|--------|------| | `PathTo(Vector2 goal)` | `bool` | 寻路到目标位置 | | `PathTo(params Vector2[] goals)` | `bool` | 寻路到多个目标中最近的 | | `UpdatePath()` | `void` | 触发重新寻路(不改变目标) | | `SetRandomDestination()` | `bool` | 设置随机目标 | | `Stop()` | `void` | 优雅停止(完成当前链接后停止) | | `ForceStop()` | `void` | 立即强制停止 | | `CompleteSegmentTraversal()` | `void` | 通知已完成线段移动(由移动组件调用) | | `CompleteLinkTraversal()` | `void` | 通知已完成链接穿越(由移动组件调用) | | `WarpToNearestSegment()` | `void` | 传送到最近线段 | | `CanTraverseLink(int linkType)` | `bool` | 检查是否可穿越指定类型链接 | | `CanReach(Vector2 goal)` | `bool` | 同步检查目标是否可达 | | `CreatePathRequest()` | `PathRequest` | 创建自定义寻路请求 | ### 4.3 公共属性 | 属性 | 类型 | 说明 | |------|------|------| | `CurrentStatus` | `NavAgentStatus` | 当前状态枚举 | | `IsIdle` | `bool` | 是否空闲 | | `IsFollowingAPath` | `bool` | 是否正在跟随路径 | | `IsOnLink` | `bool` | 是否正在链接上 | | `IsMovingOnSegment` | `bool` | 是否在线段上移动 | | `HasValidPosition` | `bool` | 当前位置是否有效(在线段上) | | `Height` | `float` | 代理高度 | | `MaxSlopeAngle` | `float` | 最大坡度角 | | `CurrentSegmentNormal` | `Vector2` | 当前线段法线 | | `PathGoal` | `Vector2` | 当前路径目标 | | `Position` | `Vector2` | 代理位置 | | `CurrentNavTagVector` | `int` | 当前位置的 NavTag | | `TimeOnLink` | `float` | 在当前链接上经过的时间 | ### 4.4 事件 | 事件 | 参数 | 触发时机 | |------|------|---------| | `OnStartLinkTraversal` | `NavAgent, PathSegment` | 开始穿越链接 | | `OnLinkTraversal` | `NavAgent, PathSegment, float t` | 链接穿越每帧回调(t: 0→1) | | `OnStartSegmentTraversal` | `NavAgent, PathSegment` | 开始线段移动 | | `OnSegmentTraversal` | `NavAgent, PathSegment, float t` | 线段移动每帧回调 | | `OnFailedToFindPath` | — | 寻路失败 | | `OnStop` | — | 停止移动 | | `OnReachedGoal` | — | 到达目标 | | `OnStartFollowingNewPath` | — | 开始跟随新路径 | ### 4.5 Inspector 配置 | 字段 | 默认值 | 说明 | |------|--------|------| | `height` | 1 | 代理高度(影响净空检查) | | `maxSlopeAngle` | 60 | 最大可行走坡度角 | | `autoRepathIntervall` | 1 | 自动重新寻路间隔(秒) | | `maximumDistanceToPathStart` | ∞ | 到路径起点的最大距离 | | `linkTraversalCostMultipliers[]` | — | 各链接类型代价乘数 | | `navTagTraversalCostMultipliers[]` | — | 各 NavTag 代价乘数 | | `allowCloseEnoughPath` | `false` | 允许"近似到达"路径 | | `enableDebugMessages` | `false` | 启用调试日志 | --- ## 5. NavSurface 详解 ### 5.1 核心概念 NavSurface 是导航数据的来源。它扫描子对象上的 **Collider2D**,沿碰撞体表面生成导航线段,并在烘焙完成后将数据添加到全局 NavGraph。 关键特性: - **自动烘焙**:编辑器中或运行时均可烘焙 - **移动平台**:烘焙数据以本地坐标存储,NavSurface Transform 移动时路径跟随 - **动态加载**:`OnEnable` 添加到 NavGraph,`OnDisable` 移除 ### 5.2 公共属性 | 属性 | 类型 | 说明 | |------|------|------| | `WorldBounds` | `Rect` | 世界空间包围盒 | | `MaxClearance` | `float` | 最大净空检查高度 | | `MinClearance` | `float` | 最小净空(低于此值的线段被移除) | | `CellSize` | `float` | 净空检查精度 | | `ColliderMask` | `LayerMask` | 碰撞体过滤层 | | `TotalLineLength` | `float` | 所有线段总长度 | | `MaxSlopeAngle` | `float` | 最大坡度角 | | `LocalToWorldMatrix` | `Matrix4x4` | 本地到世界矩阵 | ### 5.3 公共方法 | 方法 | 说明 | |------|------| | `IEnumerator Bake()` | 运行时烘焙(协程) | | `Vector2 LocalToWorld(Vector2 pos)` | 本地坐标转世界坐标 | | `Vector2 WorldToLocal(Vector2 pos)` | 世界坐标转本地坐标 | ### 5.4 事件 | 事件 | 说明 | |------|------| | `OnBakingCompleted` | 烘焙完成 | | `OnReadyToPathfind` | 已添加到 NavGraph,可以开始寻路 | | `OnRemovedFromPathfinding` | 已从 NavGraph 移除 | ### 5.5 Inspector 烘焙配置 | 字段 | 默认值 | 说明 | |------|--------|------| | `maxClearance` | 1.8 | 障碍检查最大高度 | | `minClearance` | 0.1 | 净空低于此值的线段被移除 | | `cellSize` | 0.1 | 障碍检查精度(越小越精确但越慢) | | `includedColliders` | ~0 | 参与烘焙的层 | | `onlyStaticColliders` | false | 仅包含静态碰撞体 | | `maxSlopeAngle` | 180 | 移除超过此角度的线段 | | `smallestDistanceYouCareAbout` | 0.1 | RDP 线简化容差 | | `minSegmentLength` | 0.1 | 最小线段长度 | ### 5.6 使用示例 ``` 场景层级结构: NavSurface (GameObject) ├── Ground (BoxCollider2D) ├── Platform_1 (BoxCollider2D) ├── Platform_2 (PolygonCollider2D) └── Wall (BoxCollider2D) ``` > **注意**: NavSurface 只扫描 **子对象** 上的 Collider2D,自身上的碰撞体不会被烘焙。 --- ## 6. NavLink 与 NavLinkCluster ### 6.1 NavLink — 单个导航链接 NavLink 连接两个点,代表跳跃、下落、攀爬等需要特殊处理的路径段。 #### 可视化类型 | 类型 | 说明 | |------|------| | `Linear` | 直线 | | `QuadradticBezier` | 二次贝塞尔曲线 | | `Projectile` | 抛物线 | | `Teleport` | 传送(瞬移) | | `None` | 无可视化 | | `TransformBasedMovement` | 使用 TransformBasedMovement 的默认处理 | #### 公共属性 | 属性 | 类型 | 说明 | |------|------|------| | `GoalWorldPosition` | `Vector2` | 目标世界位置(可读写) | | `StartWorldPosition` | `Vector2` | 起点世界位置(可读写) | | `IsBidirectional` | `bool` | 是否双向 | | `IsAddedToWorld` | `bool` | 是否已添加到 NavGraph | #### 公共方法 | 方法 | 说明 | |------|------| | `UpdateMapping()` | 位置改变后更新链接映射 | | `SetStartToGoalLinkTraversable(bool)` | 设置正向可穿越性 | | `SetGoalToStartLinkTraversable(bool)` | 设置反向可穿越性 | #### 共有基类属性 (BaseNavLink) | 属性 | 说明 | |------|------| | `LinkType` | 链接类型索引(corner=0, jump=1, fall=2, teleport=3, climb=4, elevator=5) | | `Clearance` | 允许通过的最大代理高度 | | `AvgWaitTime` | 平均等待时间(影响寻路代价) | | `CostOverride` | 代价覆盖(≤0 使用距离计算) | | `NavTag` | NavTag 标记 | | `MaxTraversableDistance` | 最大可穿越距离 | | `autoMap` | 自动映射到 NavGraph | ### 6.2 NavLinkCluster — 链接集群 NavLinkCluster 适用于多点互联场景,如 **电梯**(多层站点)、**梯子**(多个停靠点)。 内部为每对点自动生成一个链接。 #### LinkPoint 结构 ```csharp struct LinkPoint { Vector2 point; PointTraversalType traversalType; // Exit | Entry | Both } ``` #### 公共方法 | 方法 | 说明 | |------|------| | `UpdateMapping()` | 更新所有链接映射 | | `SetLinksTraversable(Func)` | 根据起终点函数设置各链接可穿越性 | #### 使用场景 ```csharp // 电梯到达某层时,只允许穿越与该层相关的链接 navLinkCluster.SetLinksTraversable((start, goal) => Mathf.Abs(start.y - currentFloor.position.y) < 0.1f || Mathf.Abs(goal.y - currentFloor.position.y) < 0.1f); // 离开时禁用所有链接 navLinkCluster.SetLinksTraversable((start, goal) => false); ``` --- ## 7. 辅助组件 ### 7.1 NavAreaMarker — 区域标记 **要求**: `RectTransform` 将矩形区域内的所有导航线段标记为指定 NavTag。常用于标记水域、危险区域、门区域等。 | 属性/方法 | 说明 | |-----------|------| | `NavTag` | NavTag 索引 | | `MarkerColor` | 标记颜色 | | `updateAfterTimeOfNoMovement` | 停止移动后更新延迟 | | `updateAfterTime` | 最大更新间隔 | | `UpdateMappings()` | 手动更新映射 | **门控模式**: 通过启用/禁用 NavAreaMarker 来控制门的通行: ```csharp // 开门 → 禁用标记 → 代理可通过 navAreaMarker.enabled = false; // 关门 → 启用标记 → 区域被标记为不可通行 NavTag navAreaMarker.enabled = true; ``` ### 7.2 NavSegmentSubstractor — 线段裁剪器 **要求**: `RectTransform` 在烘焙时从指定矩形区域移除线段。支持角度过滤: | 字段 | 说明 | |------|------| | `fromAngle` | 最小角度过滤 | | `toAngle` | 最大角度过滤 | ### 7.3 DynamicObstacle — 动态障碍物 空标记组件。附加到 GameObject 上,使其在 NavSurface 烘焙时被忽略。 ### 7.4 IVelocityProvider — 速度接口 ```csharp interface IVelocityProvider { Vector2 WorldVelocity { get; } } ``` 用于 `Follower` 组件的目标预测功能。在跟随目标上实现此接口即可。 --- ## 8. 全局系统 — PBWorld 与 Settings ### 8.1 PBWorld — 全局单例 自动实例化,`DontDestroyOnLoad`。管理全局 NavGraph 和寻路调度。 #### 静态 API ```csharp // === 点映射 === // 映射世界点到最近导航位置 static bool TryMapPoint(Vector2 position, out NavSegmentPositionPointer pointer) // 自定义搜索半径 static bool TryMapPoint(Vector2 position, float searchRadius, out NavSegmentPositionPointer pointer) // 确保映射位置对代理可通行 static bool TryMapPoint(Vector2 position, float searchRadius, NavAgent agent, out NavSegmentPositionPointer pointer) // === 随机 === static Vector2 GetRandomPointOnGraph() // 返回图上随机点 // === 寻路 === static void PathTo(PathRequest pathRequest) // 入队异步寻路请求 // === 空间查询 === static List BoxCast(Rect rect, float rotation, float fromAngle, float toAngle) // === 图变化监听 === static INavGraphChangeSource NavGraphChangeSource // 订阅 OnGraphChange 事件 ``` #### NavGraphChange 事件枚举 | 值 | 说明 | |----|------| | `NavSurfaceAdded` | NavSurface 添加 | | `NavSurfaceRemoved` | NavSurface 移除 | | `NavLinkAdded` | NavLink 添加 | | `NavLinkRemoved` | NavLink 移除 | | `SegmentModifierAdded` | 线段修改器添加 | | `SegmentModifierRemoved` | 线段修改器移除 | | `NavLinkMoved` | NavLink 位置变更 | ### 8.2 NavSegmentPositionPointer 导航位置指针结构体,用于表示一个在导航图上的有效位置: | 属性 | 类型 | 说明 | |------|------|------| | `Position` | `Vector2` | 世界位置 | | `Normal` | `Vector2` | 法线 | | `IsValid()` | `bool` | 是否有效 | | `IsInvalid()` | `bool` | 是否无效 | --- ## 9. 路径与寻路请求 ### 9.1 PathRequest — 寻路请求 | 枚举 | 值 | |------|-----| | **RequestState** | `Draft`, `Pending`, `Finished`, `Failed` | | **RequestFailReason** | `CouldntMapStart`, `CouldntMapGoal`, `MappedStartChanged`, `AllMappedGoalsChanged`, `NoPathFromStartToGoal`, `WorldWasDestroyed`, `ToFarFromStart` | | 属性 | 类型 | 说明 | |------|------|------| | `Status` | `RequestState` | 请求状态 | | `FailReason` | `RequestFailReason` | 失败原因 | | `Path` | `Path` | 计算出的路径 | | `start` | `NavSegmentPositionPointer` | 起点 | | `goals` | `IList` | 目标列表 | | `client` | `NavAgent` | 请求代理 | ### 9.2 Path — 路径 | 属性/方法 | 说明 | |-----------|------| | `Current` | 当前路径片段 (`PathSegment`) | | `NextSegment` | 下一个片段 | | `HasNext` | 是否有下一个 | | `Goal` | 目标位置 | | `Start` | 起点位置 | | `totalCosts` | 总代价 | | `MoveNext()` | 前进到下一片段 | | `AllPathPoints()` | 获取所有路径点列表 | | `RemainingPathPoints()` | 获取剩余路径点列表 | ### 9.3 PathSegment — 路径片段 | 属性/方法 | 说明 | |-----------|------| | `Next` | 下一个片段 | | `LinkStart` | 链接起点(世界坐标,随 NavSurface 移动) | | `LinkEnd` | 链接终点 | | `Normal` | 线段法线 | | `Tangent` | 线段切线 | | `Point` | 线段上的参考点 | | `link` | 关联的链接实例 | | `owner` | 所属 NavSurface | | `GetTagVector(float t)` | 获取位置的 NavTag | | `DistanceAlongSegment(Vector2 pos)` | 投影距离 | --- ## 10. 预置行为脚本 PathBerserker2d 提供 8 个即用的 NavAgent 行为脚本: | 组件 | 说明 | 典型用途 | |------|------|---------| | **MouseWalker** | 鼠标点击处寻路 | 调试、点击移动原型 | | **PatrolWalker** | 按顺序巡逻路线,循环 | 巡逻敌人 | | **RandomWalker** | 持续随机行走 | NPC 闲逛 | | **MultiGoalWalker** | 寻路到多个目标中最近的一个 | 收集物搜索 | | **Follower** | 跟随目标 Transform,支持目标预测 | 追踪型敌人 | | **KeepGrounded** | 通过 Raycast 检测移动平台并 parent | 移动平台上的代理 | | **AdjustRotation** | 旋转代理匹配线段法线方向 | 沿曲面行走的方向适配 | | **FootStepSounds** | 根据 NavTag 播放不同脚步声 | 环境音效 | ### 使用方式 直接将这些脚本添加到带有 NavAgent 的 GameObject 上即可。它们自动获取同 GameObject 上的 NavAgent 引用。 --- ## 11. TransformBasedMovement 移动系统 ### 11.1 概述 `TransformBasedMovement` 是 PathBerserker2d 提供的默认移动实现。它订阅 NavAgent 的事件,在回调中直接修改 Transform 位置,并在完成后调用 `CompleteSegmentTraversal()` / `CompleteLinkTraversal()` 通知 NavAgent。 ### 11.2 FeatureFlags ```csharp [Flags] enum FeatureFlags { SegmentMovement = 1, // 线段移动 JumpLinks = 2, // 跳跃链接 CornerLinks = 4, // 拐角链接 FallLinks = 8, // 下落链接 TeleportLinks = 16, // 传送链接 ClimbLinks = 32, // 攀爬链接 ElevatorLinks = 64, // 电梯链接 OtherLinks = 128, // 其他链接 } ``` ### 11.3 配置属性 | 字段 | 默认值 | 说明 | |------|--------|------| | `movementSpeed` | 5 | 线段移动速度 (unit/s) | | `cornerSpeed` | 100 | 拐角链接速度 (degrees/s) | | `jumpSpeed` | 5 | 跳跃速度 (unit/s) | | `fallSpeed` | 5 | 下落速度 (unit/s) | | `climbSpeed` | 5 | 攀爬速度 (unit/s) | | `enableAgentRotation` | true | 是否旋转代理朝向移动方向 | | `enabledFeatures` | 全部启用 | 控制由本组件处理的功能 | ### 11.4 自定义移动组件 如果 `TransformBasedMovement` 不满足需求(例如需要物理驱动移动),可以创建自定义移动组件: ```csharp public class CustomMovement : MonoBehaviour { NavAgent navAgent; void Awake() => navAgent = GetComponent(); void OnEnable() { navAgent.OnStartSegmentTraversal += HandleSegmentStart; navAgent.OnSegmentTraversal += HandleSegmentMove; navAgent.OnStartLinkTraversal += HandleLinkStart; navAgent.OnLinkTraversal += HandleLinkMove; } void HandleSegmentMove(NavAgent agent, PathSegment seg, float t) { // 自定义线段移动逻辑 // ... // 完成后: agent.CompleteSegmentTraversal(); } void HandleLinkMove(NavAgent agent, PathSegment seg, float t) { // 自定义链接穿越逻辑 // ... // 完成后: agent.CompleteLinkTraversal(); } } ``` --- ## 12. Demo 场景与使用模式 ### 12.1 Demo 场景一览 | 场景 | 展示内容 | |------|---------| | `breakable_wall` | 可破坏墙壁 + 寻路 | | `door` | NavAreaMarker 门控 | | `elevator` | NavLinkCluster 电梯系统 | | `follow_target` | Follower 跟随行为 | | `ladder` | 攀爬链接 | | `moving_platform` | 移动平台导航 | | `multi_surface` | 多 NavSurface 场景 | | `procedural_endless_jumper` | 运行时烘焙 | | `runtime_bake` | 运行时动态烘焙 | | `simple_patrol` | 基础巡逻 | | `teleport` | 传送链接 | | `threesixtydegree` | 360° 全向导航 | | `trafficlight` | 交通灯 + 等待逻辑 | | `tricky_jump` | 复杂跳跃场景 | ### 12.2 常用使用模式 #### 模式 1:最简单的寻路 ```csharp // GoalWalker 模式:检查距离 + IsIdle → PathTo void Update() { if (Vector2.Distance(goal.position, navAgent.transform.position) > 0.5f && (navAgent.IsIdle || goal.hasChanged)) { goal.hasChanged = false; navAgent.PathTo(goal.position); } } ``` #### 模式 2:电梯 — 动态链接切换 ```csharp // 电梯到达某层 → 启用相关链接 navLinkCluster.SetLinksTraversable((start, goal) => Mathf.Abs(start.y - levels[nextLevel].position.y) < 0.1f || Mathf.Abs(goal.y - levels[nextLevel].position.y) < 0.1f); // 电梯离开 → 禁用所有链接 navLinkCluster.SetLinksTraversable((start, goal) => false); ``` #### 模式 3:门 — NavAreaMarker 控制 ```csharp // 开门:禁用 NavAreaMarker → 区域不再有阻挡标记 navAreaMarker.enabled = false; // 关门:启用 NavAreaMarker → 门区域被标记为不可通行 NavTag navAreaMarker.enabled = true; ``` #### 模式 4:移动平台 ```csharp // MovingPlatform 是 NavSurface 的子对象 // 只需移动 NavSurface 的 Transform,导航数据自动跟随 transform.Translate(velocity * Time.deltaTime); ``` #### 模式 5:运行时烘焙 ```csharp // 在运行时触发烘焙 StartCoroutine(navSurface.Bake()); // 监听烘焙完成 navSurface.OnBakingCompleted += () => Debug.Log("Bake done!"); navSurface.OnReadyToPathfind += () => Debug.Log("Ready for pathfinding!"); ``` --- ## 13. Corgi 引擎集成 PathBerserker2d 附带 **CorgiBasedMovement** 组件,替代 `TransformBasedMovement` 以对接 Corgi Engine 的角色控制系统。 ### 13.1 核心映射 | 导航行为 | Corgi 映射 | |---------|-----------| | 线段移动 | `CharacterHorizontalMovement.SetHorizontalMove()` | | 跳跃链接 | `CharacterJump.JumpStart()` | | 攀爬链接 | `CharacterLadder`(反射调用) | | 传送链接 | 直接设置 Position | | 拐角链接 | 直接 `CompleteLinkTraversal()` | | 卡住检测 | `fallbackTeleportDelay` 秒后传送 | ### 13.2 Corgi AI Actions | 脚本 | 说明 | |------|------| | `AIActionPBMoveTowardsTarget` | 移向目标 | | `AIActionPBMoveTowardsClosestTarget` | 移向最近目标 | | `AIActionPBMoveTowardsRandomPathableTarget` | 移向可达随机目标 | | `AIActionPBPatrol` | 巡逻 | | `AIDecisionPBHasReachedGoal` | 判断是否到达 | | `AIDecisionPBPathfindingFailed` | 判断寻路失败 | > **注意**: 本项目使用自研架构而非 Corgi Engine,此集成仅作参考。 --- ## 14. 全局设置参考 **位置**: `Edit > Project Settings > PathBerserker2d` **资源文件**: `Assets/PathBerserker2d/Resources/PathBerserker2dSettings` ### 14.1 设置项 | 属性 | 类型 | 当前值 | 说明 | |------|------|--------|------| | `PointMappingDistance` | float | 0.2 | 点映射最大距离(性能关键,应尽量小) | | `PathfinderThreadCount` | int | 4 | 寻路线程数(WebGL 强制 = 1) | | `InitiateUpdateInterval` | float | 0.1s | NavGraph 更新间隔 | | `DrawGraphWhilePlaying` | bool | — | 运行时绘制导航图 | | `NavSurfaceLineWidth` | float | — | 线宽 | | `UsePolygonCollider2dPathsForBaking` | bool | — | 多边形碰撞体烘焙方式 | ### 14.2 内置链接类型 | 索引 | 名称 | 说明 | |------|------|------| | 0 | `corner` | 拐角(自动生成) | | 1 | `jump` | 跳跃 | | 2 | `fall` | 下落 | | 3 | `teleport` | 传送 | | 4 | `climb` | 攀爬 | | 5 | `elevator` | 电梯 | ### 14.3 内置 NavTag | 名称 | 用途 | |------|------| | `default` | 默认 | | `water` | 水域 | | `lava` | 岩浆 | | `grass` | 草地 | | `concrete` | 混凝土 | | `dirt` | 泥土 | --- ## 15. 与 BaseGames 架构集成方案 ### 15.1 防腐层原则 根据 BaseGames 架构总纲(`00_Architecture_Overview.md`)第 3 条设计理念: > **防腐层隔离**: 业务代码永远不直接调用 PathBerserker2d 等第三方 API。所有第三方交互通过 `Adapters/` 层代理。 因此 PathBerserker2d 的所有功能必须通过 **适配器层** 暴露给业务系统。 ### 15.2 适配器设计 ``` Layer 3 — Adapters/ └── NavAgentAdapter.cs # PathBerserker2d NavAgent 的防腐包装 业务层调用链: EnemyAI (Layer 5) → NavAgentAdapter (Layer 3) → NavAgent (第三方) ``` #### NavAgentAdapter 接口建议 ```csharp namespace BaseGames.Adapters { /// /// PathBerserker2d NavAgent 的防腐层适配器。 /// 业务代码通过此接口进行寻路,不直接引用 PathBerserker2d API。 /// public interface INavigation { bool PathTo(Vector2 goal); bool PathTo(params Vector2[] goals); void Stop(); void ForceStop(); bool IsIdle { get; } bool IsFollowingPath { get; } bool CanReach(Vector2 goal); Vector2 CurrentPosition { get; } event Action OnReachedGoal; event Action OnPathFailed; event Action OnStopped; } } ``` ### 15.3 与其他系统的集成点 | BaseGames 系统 | 集成方式 | |----------------|---------| | **敌人 AI (20_Enemy_AI)** | 行为树通过 `INavigation` 接口调用寻路 | | **环境系统 (11_Environment)** | MovingPlatform 使用 NavSurface 子对象模式 | | **环境系统 (11_Environment)** | BreakableWall 销毁后触发 NavSurface 重新烘焙 | | **环境系统 (11_Environment)** | TeleportGate 对应 NavLink(teleport 类型) | | **物理动画 (08_Physics)** | 自定义移动组件桥接 `IPhysicsBody` 与 NavAgent 事件 | | **标签系统 (02_GameTag)** | NavTag 可映射为 GameTagSO 用于环境效果触发 | ### 15.4 自定义移动组件集成 由于 BaseGames 使用自研物理系统 (`IPhysicsBody` / `RaycastBody2D`),不应使用默认的 `TransformBasedMovement`。需要创建桥接移动组件: ```csharp namespace BaseGames.Adapters { public class PhysicsBasedNavMovement : MonoBehaviour { // 订阅 NavAgent 事件 // 将移动指令转发给 IPhysicsBody // 通过 IPhysicsBody 驱动实际移动 // 移动完成后调用 CompleteSegmentTraversal() / CompleteLinkTraversal() } } ``` --- ## 16. 性能分析与优化建议 ### 16.1 性能特性 | 方面 | 评估 | |------|------| | **寻路** | 多线程 A\*,不阻塞主线程。线程数可配置(默认 4) | | **烘焙** | 协程方式,可分帧执行。复杂场景烘焙较重 | | **内存** | 线段数据以本地坐标存储,紧凑 | | **空间索引** | B2DynamicTree(Box2D 动态树),查询高效 | | **WebGL** | 自动降级为单线程协程模式 | ### 16.2 优化建议 | 建议 | 说明 | |------|------| | **减小 `PointMappingDistance`** | 当前 0.2,越小映射查询越快 | | **调整 `autoRepathIntervall`** | 不要过于频繁,1-2 秒通常足够 | | **合理设置 `cellSize`** | 烘焙精度越高越慢,0.1 适合大多数情况 | | **分区管理 NavSurface** | 按房间/区域拆分 NavSurface,按需启用/禁用 | | **限制同时寻路数** | 大量代理时排队处理,避免请求洪峰 | | **善用 `onlyStaticColliders`** | 排除动态碰撞体可加速烘焙 | --- ## 17. 优缺点总结 ### 17.1 优势 | 优势 | 说明 | |------|------| | **原生 2D 支持** | 基于线段而非面片,天然适合 2D 横版游戏 | | **完整源码** | 所有代码可见,便于调试和定制 | | **链接系统丰富** | 内置 6 种链接类型,覆盖跳跃/下落/攀爬/电梯/传送/拐角 | | **动态世界** | 运行时烘焙、移动平台、动态链接切换 | | **多线程寻路** | 不阻塞主线程,支持多代理并发 | | **事件驱动架构** | 移动实现完全解耦,易于替换为自定义移动系统 | | **预置行为丰富** | 8 个即用行为脚本覆盖常见场景 | | **移动平台支持** | 本地坐标体系自动跟随 NavSurface Transform 变化 | ### 17.2 不足 | 不足 | 说明 | |------|------| | **文档较简陋** | 官方文档以 Demo 为主,缺少系统性 API 文档 | | **无官方维护迹象** | Asset Store 版本更新不频繁 | | **烘焙仅支持 Collider2D** | 不支持 Tilemap 直接烘焙(需转换为 Collider) | | **链接需手动放置** | 跳跃/攀爬等链接需要手动在编辑器中放置 | | **360° 模式限制** | 虽支持 360° 但主要为横版优化 | | **缺少动态避障** | 无 RVO / ORCA 等动态避障实现 | | **NavTag 数量有限** | 内置 6 个 NavTag,扩展需修改设置 | ### 17.3 技术评分 | 维度 | 评分 (1-10) | 说明 | |------|-------------|------| | 2D 适配度 | **9** | 专为 2D 设计,线段导航非常贴合横版场景 | | API 设计 | **8** | 事件驱动架构清晰,易于扩展 | | 文档质量 | **5** | Demo 丰富但系统文档不足 | | 性能 | **8** | 多线程寻路 + B2DynamicTree 空间索引 | | 易用性 | **7** | 基础使用简单,高级功能学习曲线稍陡 | | 可维护性 | **7** | 完整源码可见,但注释较少 | | 扩展性 | **8** | 事件驱动 + 接口隔离,易接入自定义系统 | | **综合** | **7.4** | 适合 2D Metroidvania 项目的可靠寻路方案 | --- ## 18. 总结与建议 ### 18.1 总体评价 PathBerserker2d 是目前 Unity 生态中少有的 **专为 2D 横版设计** 的寻路方案。其基于线段的导航模型天然适配平台跳跃类游戏,多线程异步寻路保证了性能,事件驱动架构提供了良好的扩展性。 对于 BaseGames 这样的 2D Metroidvania 项目,它提供了: - **完整的 2D 导航能力**:地面行走、跳跃、下落、攀爬、电梯、传送 - **移动平台支持**:天然适配关卡中的动态地形 - **与自定义物理系统的解耦**:通过事件驱动架构可桥接 `IPhysicsBody` ### 18.2 集成建议 1. **严格通过适配器层访问** — 遵循 BaseGames 防腐层原则,创建 `NavAgentAdapter` / `INavigation` 接口 2. **替换 TransformBasedMovement** — 创建 `PhysicsBasedNavMovement` 桥接 `IPhysicsBody` 3. **按房间分区 NavSurface** — 配合关卡加载系统,按需启用/禁用导航区域 4. **NavTag 映射 GameTagSO** — 统一标签体系,复用效果系统触发逻辑 5. **行为树集成** — 通过 `INavigation` 接口在行为树节点中调用寻路 ### 18.3 注意事项 - 可破坏墙壁销毁后需触发 NavSurface 重新烘焙 - 电梯/升降台需使用 NavLinkCluster 配合动态可穿越性控制 - 大量 AI 代理场景需排队管理寻路请求避免性能瓶颈 - WebGL 构建时自动降级为单线程,需额外测试性能