寻路与移动
船员在甲板格子上用分层 A* 找路、以固定 3.3 格/秒沿路径行走;船只在海面上用基于推力与阻力的物理模型移动,速度由引擎功率、船体质量和船长在岗状态共同决定。
本页覆盖游戏中两套互相独立的移动体系:
- 船内格子寻路(船员):船员不可直接操控(参考 RimWorld),玩家通过下达工作、建造、搬运等任务间接驱动船员移动(见 任务与工作)。任务系统的“移动”步骤把目标格子交给船员身上的寻路代理(
PathfindingAgent.cs),代理向寻路管理器(PathfindingManager.cs)请求路径,由分层 A* 算法(HierarchicalAStar.cs)在船体网格上计算,然后船员逐格走过去。 - 海面船只移动(船体):玩家用方向键直接操舵,或按 F 全速前进、按 N 进入自动导航。船的实际速度不是固定值,而是由引擎总功率、船体质量、船长是否在岗实时算出(
MovementController.cs、ShipEngineBinding.cs)。
怪物在海面上的移动不使用本页的格子寻路系统,详见怪物。
在游戏循环中的位置:寻路是几乎所有玩法的底层依赖——搬运、修建、制作、吃饭、睡觉,每一步“走过去”都经过它;寻路失败直接导致任务失败,是“船员站着不动”类问题的头号嫌疑人。玩家对寻路系统本身没有直接操作入口,能感知到的是:船员绕路、在门前停顿半秒等门、拆地板后当场改道、目标被围死时任务失败原地不动。
关键架构事实:每艘船拥有一套独立的寻路系统(网格、管理器、动态更新器各一份;AI 船由 AIShipFactory.cs 程序化组装)。船员只能在自己所在的船内寻路,不存在跨船找路。
一、格子系统与可走性判定
Section titled “一、格子系统与可走性判定”寻路网格与建筑系统共享同一套格子坐标系(GridManager.cs):
| 项目 | 玩家船 | AI 船 | 来源 |
|---|---|---|---|
| 水平范围 | 100 × 100 格 | 50 × 50 格 | 玩家船:Inspector(mvp_002 场景 xCount/zCount);AI 船:代码常量(AIShipFactory.cs) |
| 单格尺寸 | 1 米 | 1 米 | Inspector(gridSize) |
| 甲板层数 | Deck -5 至 Deck 5,共 11 层 | 同左 | Inspector(minDeck/maxDeck) |
关键设计:寻路坐标全部是相对船体的本地网格坐标,不是世界坐标(PathData.cs)。路径算出之后即使船在海上高速移动、旋转,船员脚下的路径会自动跟随船体,无需重新寻路。
可走性规则(PathfindingGrid.cs 的 CheckWalkability)
Section titled “可走性规则(PathfindingGrid.cs 的 CheckWalkability)”一个格子可走,当且仅当同时满足:
- 格子上有已完工的地板(建筑层级为 Floor 且状态为 Completed)。还在施工中的“框架”状态地板不可走。
- 格子上没有阻挡型设施(建筑层级为 Facility:工作台、引擎、墙壁、床、火炮等都属于此层,见建筑)。注意设施不检查完工状态——刚下蓝图、还在施工的设施就已经阻挡寻路了。
两类设施例外,不阻挡寻路:
- 楼梯:名称中包含 stair / ladder / 楼梯 / 梯子(不区分大小写)的设施视为可走。
- 门:挂有门组件(
DoorComponent.cs)的设施永远视为可走——门的开/关不改变寻路图,船员走到门前再等门开(见下文“自动门”)。
管道(Pipe)、顶灯(Light)、房间(Room)层级的建筑不参与可走性判定(BuildingLayer.cs)。
移动连接规则
Section titled “移动连接规则”| 规则 | 内容 | 出处 |
|---|---|---|
| 水平移动 | 仅四方向(前后左右),不支持斜向移动 | PathfindingConstants.cs |
| 垂直移动 | 仅通过楼梯:楼梯格与其正上方一格建立双向垂直连接;两个格子都必须可走(即上层也要有地板)才能建立 | PathfindingGrid.cs |
| 移动成本 | 所有方向每格成本均为 1(水平=垂直) | HierarchicalAStar.cs |
| 启发式距离 | 三维曼哈顿距离 | PathfindingNode.cs |
注意:建立垂直连接时识别楼梯用的是精确名称名单(Stair、Stairs、楼梯、Ladder、梯子、StairBlock、LadderBlock、TestStair、AutoStair),而可走性判定用的是名称包含匹配,两处标准不一致(见“已知限制”第 4 条)。
二、分层寻路(Cluster + Gateway)
Section titled “二、分层寻路(Cluster + Gateway)”为了让 100×100×11(共 110000 节点)的大网格寻路足够快,网格被切成分簇(Cluster):
- 每个 Cluster 为 10×10 格 × 1 层甲板(
PathfindingConfig.asset的clusterSize=10)。玩家船当前共 10 × 10 × 11 = 1100 个 Cluster。 - 相邻 Cluster 之间通过**网关(Gateway)**连接:网关是一对经过验证、确实相邻且都可走的边界格子(
ClusterGateway.cs、GatewayManager.cs)。跨层网关建立在楼梯的垂直连接上。 - 每个 Cluster 内部预计算“任意格子 → 各网关”的路径并缓存(
IntraClusterPathCache.cs),跨簇寻路时直接拼接预计算路径。
寻路时分两种情况(HierarchicalAStar.cs):
起点与终点在同一 Cluster → 直接在簇内跑普通 A*起点与终点跨 Cluster → 先在 Cluster 层面跑一遍 A*(把整个簇当节点、网关当边), 得到簇序列后,再用簇内预计算路径逐段细化成逐格路径搜索量上限(超限即寻路失败):
| 搜索层级 | 上限 | 出处 |
|---|---|---|
| 格子级 A*(同簇) | 5000 个节点(maxSearchNodes) |
PathfindingConfig.asset |
| 簇级 A*(同层跨簇) | min(总簇数 ÷ 2, maxSearchNodes ÷ 10) = min(550, 500) = 500 个簇 | 代码逻辑(HierarchicalAStar.cs) |
| 簇级 A*(跨甲板层) | 不限(允许搜完全部 1100 个簇) | 代码逻辑(HierarchicalAStar.cs) |
细化完成后还有一道路径连续性校验:路径中任意相邻两点必须恰好相差 1 格(四向连续),否则整条路径作废、按寻路失败处理(HierarchicalAStar.cs 的 ValidateGridPathContinuity)。
“分层寻路已禁用”的现状澄清
Section titled ““分层寻路已禁用”的现状澄清”项目根目录 CLAUDE.md 的 Known Issues 写有“HierarchicalAStar.cs:176:分层寻路暂时禁用”。这条记录已过时:旧版本(2026 年 5 月 10 日之前)确实在跨簇分支上用世界坐标回退方案并留有“暂时禁用了分层寻路”的注释,但当前代码已重构为跨簇路径直接返回网格坐标,跨 Cluster 分层寻路是启用且生效的。遗留问题是:“跨 Cluster + 船体处于旋转状态”的回归测试仍被标记忽略(HierarchicalAStarV2PlayModeTests.cs 中的 [Ignore]),该场景的正确性目前没有自动化测试保障。
三、寻路请求流程:什么时候找不到路、表现是什么
Section titled “三、寻路请求流程:什么时候找不到路、表现是什么”- 任务系统的“移动”步骤(
Steps.Goto.cs)调用船员寻路代理的 SetDestination。 - 请求进入队列,最多同时处理 20 个请求(
maxConcurrentRequests,PathfindingConfig.asset);实际寻路计算在后台线程执行,不卡主线程。 - 处理时起点实时取船员当前位置(解决船移动期间排队导致的坐标过期问题);终点在入队时就锁定为网格坐标。
- 路径算出后缓存:以(起点格, 终点格)为键,缓存上限 200 条,超限裁剪到 150 条(代码常量,
PathfindingManager.cs);因为存的是本地坐标,缓存不会因船移动而过期,只在建筑变化时按受影响格子失效。
起点/终点自动修正
Section titled “起点/终点自动修正”- 终点格子不可走(比如目标设施周围被拆)时,系统以终点为中心螺旋向外搜索最多 5 格(仅同一层甲板),找到最近的可走格作为替代终点;找不到才判失败(
PathfindingGrid.cs的 GetNearestWalkableNode)。 - 起点同样做最近可走格修正(半径同为 5 格、仅同层)。
这意味着船员可能走到离原目标最远 5 格的替代点而没有任何提示。
找不到路的全部情形
Section titled “找不到路的全部情形”| 情形 | 典型场景 | 出处 |
|---|---|---|
| 终点 5 格内无可走格 | 目标点周围地板全拆光 | PathfindingManager.cs |
| 起点 5 格内无可走格 | 船员被困在无地板区域(理论上不应发生) | HierarchicalAStar.cs |
| 起点或终点所在 Cluster 没有任何网关 | 一块与全船断开的孤立地板平台 | HierarchicalAStar.cs |
| 簇级搜索超限仍未到达 | 同层跨簇搜索超过 500 个簇 | HierarchicalAStar.cs |
| 格子级搜索超限 | 同簇搜索超过 5000 个节点 | HierarchicalAStar.cs |
| Cluster 内部存在孤岛 | 同一个 10×10 簇内被墙隔成两块、网关在另一块上;错误日志会建议“放置连续地板或调小 ClusterSize” | HierarchicalAStar.cs |
| 路径连续性校验失败 | 算法缺陷兜底,整条路作废 | HierarchicalAStar.cs |
| 请求超时 | 单次寻路请求超过 8 秒未返回(代码常量 PathRequestTimeoutSeconds) | PathfindingAgent.cs |
| 寻路系统未就绪 | 开局网格初始化未完成(管理器最多等网格 10 秒,超时则整个寻路系统停用,代码常量) | PathfindingManager.cs |
- 寻路代理触发“寻路失败”事件,船员原地不动。
- 任务系统的移动步骤判定失败(失败原因记录为“寻路失败”),整个任务按任务框架的失败流程处理(见 任务与工作)。
- Console 输出错误日志(含起终点坐标和失败原因);同时每次寻路请求的成功/失败/耗时都会写入持久化目录下的
PathfindingStats_时间戳.txt统计文件(PathfindingStatsLogger.cs),排查问题时可查。
四、船员沿路径移动
Section titled “四、船员沿路径移动”路径到手后,船员每帧逐航点推进(PathfindingAgent.cs):
| 参数 | 数值 | 含义 | 来源 |
|---|---|---|---|
| 移动速度 | 3.3 格/秒(1 格 = 1 米) | 所有船员统一;没有任何负重、心情、受伤减速修正 | PathfindingConfig.asset 的 defaultMoveSpeed(Inspector 可改) |
| 转身速度 | 10/秒 | 朝向插值速率(四元数球面插值系数,不是度/秒) | PathfindingConfig.asset 的 defaultRotationSpeed |
| 航点到达判定 | 0.5 格 | 距当前航点小于此值即切到下一航点 | PathfindingConfig.asset 的 waypointReachDistance |
| 单帧步长保护 | min(速度 × 帧时长, 剩余距离) | 高倍速下防止越过航点来回抖动 | 代码逻辑(PathfindingAgent.cs) |
船员有父物体(即在船上)时按船体本地坐标移动,完全不受船体平移/旋转影响。
游戏时间倍速(见 时间与调度)通过引擎全局时间缩放实现,等比例加速所有移动(船员、船只、子弹、怪物)(GameSpeedManager.cs)。
自动门交互(RimWorld 模式)
Section titled “自动门交互(RimWorld 模式)”门永远在寻路图中可走,开关门完全由通行行为驱动(DoorComponent.cs、PathfindingAgent.cs):
- 船员的下一个航点是关着的门 → 申请开门并原地等待。
- 开门动作耗时 0.5 秒(
_openDelay,Door.prefab Inspector 序列化字段),到时门变为打开,船员继续走。 - 船员实际跨过门格时刷新“最后通过时间”。
- 门打开后,距最后一次有人通过 ≥ 3 秒 且门所占格子上没有任何船员时,自动关门(
_autoCloseDelay,Door.prefab Inspector)。 - 门的状态检查频率为每秒 5 次(开/关门时刻有最多 0.2 秒的判定粒度),计时用与游戏暂停同步的 Tick 时间。
- 等门期间门被摧毁(如战斗中)→ 等待状态解除,交给动态更新系统重新规划路径。
玩家不能手动开关门。
五、动态障碍与重新寻路
Section titled “五、动态障碍与重新寻路”建筑的建造/拆除随时改变可走性。动态更新协调器(PathfindingDynamicUpdater.cs)监听建筑变化事件,处理流程:
- 批量合并:变化先进待处理队列,100 毫秒窗口内的多次变化合并为一批处理(
batchWindowTime,Inspector 序列化字段,默认 0.1 秒)。 - 受影响范围 = 建筑占用的所有格子 + 每个格子的四方向邻格。
- 脚下豁免:正站在受影响格子上的船员,其脚下格子暂不更新(防止拆船员脚下地板导致其瞬间“悬空不可走”);用引用计数处理多名船员连续经过的情况,等最后一名船员离开该格后再补更新。
- 楼梯增删 → 同步增删对应的垂直连接。
- 受影响 Cluster 及其相邻 Cluster:清理失效网关、清空簇内路径缓存、重新发现网关、重算预计算路径。
- 按受影响格子清除全局路径缓存。
- 自动重规划:所有“正在移动且剩余路径经过受影响格子”的船员,自动以原目标重新寻路(被豁免的船员除外)。重规划成功会触发路径重规划事件(开发调试用的路径线会黄色闪烁 3 次、间隔 0.3 秒,
PathVisualizationController.cs)。
对策划的含义:拆墙/铺地板的瞬间,全船相关船员会在 0.1 秒批量窗口后统一改道;如果改道后无路可走,则按上文寻路失败处理。
六、船只海上移动
Section titled “六、船只海上移动”船体移动与格子寻路完全无关,是一套刚体物理模型(MovementController.cs)。
| 操作 | 效果 | 出处 |
|---|---|---|
| 方向键 上/下 | 前进/后退(注意:实际绑定是方向键,不是 WASD;代码注释里的 WASD 描述已过时) | MovementInputActions.cs |
| 方向键 左/右 | 转舵 | MovementInputActions.cs |
| F 键 | 全速前进开关(等价于按住前进键,不影响转向) | FullSpeedAheadController.cs |
| N 键 | 自动导航:手动→提示打开地图选目标 / 自动中→暂停 / 暂停中→恢复 | ShipNavigationController.cs |
| 进入建造模式 | 操舵键盘输入自动禁用,退出后恢复 | MovementController.cs |
速度从哪来:引擎功率 → 速度倍率
Section titled “速度从哪来:引擎功率 → 速度倍率”船的基准速度不是常量,由引擎绑定组件每物理帧重算(ShipEngineBinding.cs):
总功率 TotalPower = 全船引擎有效输出之和 × 400(每台满功率引擎的功率值)质量惩罚 massPenalty = 1 / (1 + (船体质量 / 80) ^ 1.5)速度倍率 speedRatio = TotalPower^(1/3) × massPenalty (无功率时 = 0,船完全不动)船基准速度 moveSpeed = 1.715 × speedRatio (米/秒)船基准转速 rotateSpeed = 10.0 × speedRatio (度/秒)- 功率开立方根来自“海军上将系数”(功率 ∝ 速度³):堆引擎收益递减。
- 质量惩罚是连续 S 形曲线,中点 80(质量 = 80 时惩罚恰为 0.5)、陡峭度 1.5:轻船几乎无惩罚,重船显著变慢,没有速度上限封顶——小船真的快、大船真的慢。
- 校准锚点(代码注释):玩家船质量 33、1 台满功率引擎 → speedRatio ≈ 5.83 → 顶速约 10 米/秒(约 19 节)、转速约 58 度/秒(约 6 秒一圈)。
参数来源:_powerPerEngine=400、_massPenaltyMidpoint=80、_massPenaltyStiffness=1.5、_minSpeedRatio=0 为 ShipEngineBinding.cs 的 Inspector 序列化字段;BASE_MOVE_SPEED=1.715、BASE_ROTATE_SPEED=10.0 为代码常量(注释明确要求调速度感改常量、不改 prefab)。
推进与滑行物理(MovementController.cs,全部为代码常量)
Section titled “推进与滑行物理(MovementController.cs,全部为代码常量)”质量因子 massFactor = sqrt(80 / 船体质量) (重船加速慢、滑行远、转向沉)有效加速系数 = 0.30 × massFactor × 船长乘数有效角加速系数 = 0.30 × massFactor × 船长乘数推力(按住前进/后退时):速度增量 = 有效加速系数 × (目标速度 - 当前速度) × 帧时长 其中 目标速度 = 输入方向 × moveSpeed × 船长乘数松开按键后滑行:纵向速度 ×= e^(-0.12 × massFactor × 帧时长) (中型船约 25 秒滑停)横向速度恒衰减:×= e^(-0.20 × massFactor × 帧时长) (转弯保留大部分动能)松舵后角速度:×= e^(-0.50 × massFactor × 帧时长)- 加速手感锚点(代码注释):加速系数 0.30 ≈ 中型船 10 秒加速到 95% 顶速。
- 舵效与航速耦合:舵效率 = 25%(静止)线性过渡到 100%(满速)——原地几乎转不动,全速转向最灵。
- 后退时转向方向反转(符合船舶倒车直觉)。
- 松舵后角速度低于 0.5 度/秒直接归零(防重船“舵回中后还转半分钟”);操舵期间归零阈值为 0.01 度/秒。
船长在岗(CaptaincyManager.cs、CaptaincyConsts.cs,代码常量)
Section titled “船长在岗(CaptaincyManager.cs、CaptaincyConsts.cs,代码常量)”| 条件 | 效果 |
|---|---|
| 船上有存活、未失能、未瘫痪的船长(Captain 职级) | 机动乘数 1.0 |
| 船长缺岗 | 机动乘数 0.5:船速、转速、线性加速度、角加速度统一减半 |
| 缺岗持续 60 秒 | 全船船员获得“船长缺席”负面心情想法(见 船员) |
仅玩家船生效,AI 船不参与此判定。
自动导航(ShipNavigationController.cs,代码常量)
Section titled “自动导航(ShipNavigationController.cs,代码常量)”- 在地图上选定目标后,航线规划器做单层绕岛规划:能直达则单段,否则加 1 个拐点分 2 段;都不行则判“目标不可达”(绕岛逻辑见 岛屿与陆地)。
- 支持 Shift+右键追加航点(RTS 式多段航线)。
- 到达判定半径 5 米。
- 卡住检测:5 秒窗口内位移小于 1 米 → 进入“受阻”状态,停船并通知玩家。
- 自动航行期间玩家任何手动操舵输入 → 自动切换为“暂停”,再按 N 恢复;船沉没时自动导航取消。
船内寻路与网格
Section titled “船内寻路与网格”| 参数 | 数值 | 单位 | 来源 |
|---|---|---|---|
| 玩家船网格范围 | 100 × 100 × 11 层 | 格 | Inspector(mvp_002 场景 GridManager) |
| AI 船网格范围 | 50 × 50 | 格 | 代码常量(AIShipFactory.cs) |
| 单格尺寸 | 1 | 米 | Inspector(GridManager.gridSize) |
| 甲板范围 | Deck -5 ~ 5 | 层 | Inspector(GridManager.minDeck/maxDeck) |
| Cluster 尺寸 | 10×10×1 | 格×格×层 | PathfindingConfig.asset(Inspector 可改) |
| 单次格子级搜索上限 | 5000 | 节点 | PathfindingConfig.asset maxSearchNodes |
| 同层簇级搜索上限 | min(总簇数/2, 500) | 簇 | 代码常量(HierarchicalAStar.cs) |
| 跨层簇级搜索上限 | 无限制 | 簇 | 代码常量(HierarchicalAStar.cs) |
| 并发寻路请求上限 | 20 | 个 | PathfindingConfig.asset maxConcurrentRequests |
| 起/终点修正搜索半径 | 5(仅同层螺旋) | 格 | 代码常量(PathfindingGrid.cs) |
| 路径缓存上限 | 200(超限裁到 150) | 条 | 代码常量(PathfindingManager.cs) |
| 寻路请求超时 | 8 | 秒 | 代码常量(PathfindingAgent.cs) |
| 开局等待网格就绪上限 | 10 | 秒 | 代码常量(PathfindingManager.cs) |
| 每格移动成本 | 1(全方向一致) | — | 代码常量(HierarchicalAStar.cs) |
船员移动与门
Section titled “船员移动与门”| 参数 | 数值 | 单位 | 来源 |
|---|---|---|---|
| 船员移动速度 | 3.3 | 格/秒(=米/秒) | PathfindingConfig.asset defaultMoveSpeed |
| 船员转身速率 | 10 | 插值系数/秒 | PathfindingConfig.asset defaultRotationSpeed |
| 航点到达距离 | 0.5 | 格 | PathfindingConfig.asset waypointReachDistance |
| 停止距离 | 0.3(配置存在但代码未使用) | 格 | PathfindingConfig.asset stoppingDistance |
| 开门耗时 | 0.5 | 秒 | Inspector(Door.prefab _openDelay) |
| 自动关门延迟 | 3.0 | 秒(最后通过者之后,且门格无人) | Inspector(Door.prefab _autoCloseDelay) |
| 门状态检查频率 | 5 | 次/秒 | 代码常量(DoorComponent.cs) |
| 参数 | 数值 | 单位 | 来源 |
|---|---|---|---|
| 建筑变化批量窗口 | 0.1 | 秒 | Inspector(PathfindingDynamicUpdater batchWindowTime) |
| 受影响范围 | 占用格 + 四方向邻格 | 格 | 代码常量(PathfindingDynamicUpdater.cs) |
| 重规划条件 | 正在移动 且 剩余路径经过受影响格 | — | 代码常量(PathfindingDynamicUpdater.cs) |
船只物理(全部代码常量,MovementController.cs)
Section titled “船只物理(全部代码常量,MovementController.cs)”| 参数 | 数值 | 含义 |
|---|---|---|
| ACCEL_COEFFICIENT | 0.30 | 线性加速系数(中型船约 10 秒到 95% 顶速) |
| ANGULAR_ACCEL_COEFFICIENT | 0.30 | 角加速系数 |
| DRAG_COEFFICIENT | 0.12 | 松手纵向阻力(中型船约 25 秒滑停) |
| LATERAL_DRAG_COEFFICIENT | 0.20 | 横向阻力(约为纵向 1.7 倍) |
| ANGULAR_DRAG_COEFFICIENT | 0.50 | 松舵角阻力 |
| REFERENCE_MASS | 80 | 质量基准;massFactor = sqrt(80/质量) |
| 舵效范围 | 25% ~ 100% | 随“当前航速/顶速”线性过渡 |
| 松舵角速度归零阈值 | 0.5 度/秒(操舵中 0.01) | 防重船缓慢残转 |
| MovementController 默认 moveSpeed | 10 米/秒(运行时被引擎绑定每物理帧覆写) | Inspector 序列化字段 |
| MovementController 默认 rotateSpeed | 90 度/秒(同上被覆写) | Inspector 序列化字段 |
引擎与船速(ShipEngineBinding.cs)
Section titled “引擎与船速(ShipEngineBinding.cs)”| 参数 | 数值 | 来源 |
|---|---|---|
| 每台引擎满功率 | 400 | Inspector(_powerPerEngine) |
| 质量惩罚中点 | 80 | Inspector(_massPenaltyMidpoint) |
| 质量惩罚陡峭度 | 1.5 | Inspector(_massPenaltyStiffness) |
| 无动力最低速度比 | 0(完全不动) | Inspector(_minSpeedRatio) |
| 基准速度刻度 | 1.715 米/秒 每单位 speedRatio | 代码常量(BASE_MOVE_SPEED) |
| 基准转速刻度 | 10.0 度/秒 每单位 speedRatio | 代码常量(BASE_ROTATE_SPEED) |
| 速度公式 | speedRatio = (引擎有效输出之和 × 400)^(1/3) × 1/(1+(质量/80)^1.5) | 代码 |
| 校准例 | 质量 33 + 1 台满功率引擎 ≈ 顶速 10 米/秒、转速 58 度/秒 | 代码注释 |
船长在岗与自动导航(代码常量)
Section titled “船长在岗与自动导航(代码常量)”| 参数 | 数值 | 来源 |
|---|---|---|
| 船长缺岗机动乘数 | 0.5 | CaptaincyConsts.cs MissingMultiplier |
| 缺岗心情想法延迟 | 60 秒 | CaptaincyConsts.cs MissingThoughtDelaySeconds |
| 自动导航到达半径 | 5 米 | ShipNavigationController.cs ArrivalRadius |
| 卡住判定 | 5 秒内位移 < 1 米 | ShipNavigationController.cs StuckTimeWindow/StuckPositionEpsilon |
与其他系统的交互
Section titled “与其他系统的交互”- 任务与工作:唯一的寻路发起方。任务步骤“移动”调用寻路代理;寻路失败 = 步骤失败 = 任务失败;到达事件驱动步骤完成。
- 修建 / 建筑:建筑系统提供网格坐标系与占用数据,决定每格可走性;建筑增删触发动态更新与重规划。楼梯提供跨层通道,门提供受控通行。
- 船员:船员是寻路代理的唯一正式载体;船长在岗状态反过来影响船速;缺岗 60 秒触发全船负面心情。
- 船只:引擎建筑数量与有效输出、船体质量(随建筑增减变化)实时决定船速与转速;船沉没时自动导航取消。
- 时间与调度:游戏倍速等比例缩放一切移动;门的开关计时使用与暂停同步的 Tick 时间而非真实时间。
- 岛屿与陆地:自动导航的航线规划(直达检测 + 单拐点绕岛)依赖陆地多边形数据。
- 怪物:怪物移动不走本页格子寻路,自成体系。
- 遭遇与刷怪:AI 船由工厂生成时构建独立的寻路网格/管理器(
AIShipFactory.cs),AI 船上的船员用自己船的寻路系统,与玩家船互不干扰(门、网格、缓存都按船隔离)。 - 开发者工具:每次寻路请求写入持久化目录的统计文件;Scene 视图有路径 Gizmos;可选挂载路径线渲染(重规划时黄色闪烁提示,
PathVisualizationController.cs)。
配置与调参指南
Section titled “配置与调参指南”| 想调的体验 | 改哪里 | 字段 | 备注 |
|---|---|---|---|
| 船员走路快慢 | Assets/Scripts/Service/PathfindingSystem/PathfindingConfig.asset |
defaultMoveSpeed(当前 3.3) |
全体船员统一生效 |
| 船员转身灵敏度 | 同上 | defaultRotationSpeed(当前 10) |
|
| 寻路性能/失败率权衡 | 同上 | maxSearchNodes、clusterSize、maxConcurrentRequests |
簇内孤岛问题可尝试调小 clusterSize |
| 开门等待时长 | Assets/Scripts/Service/ConstructionSystem/DevAssets/Door.prefab |
_openDelay(当前 0.5 秒) |
|
| 自动关门延迟 | 同上 | _autoCloseDelay(当前 3 秒) |
|
| 建筑变化合并窗口 | 场景中 PathfindingDynamicUpdater 组件 |
batchWindowTime(当前 0.1 秒) |
|
| 船加速/滑行/转向手感 | MovementController.cs 顶部常量 |
ACCEL/DRAG/LATERAL_DRAG/ANGULAR_* | 需程序改代码;注释明确不走 prefab |
| 船整体速度刻度 | ShipEngineBinding.cs 常量 |
BASE_MOVE_SPEED、BASE_ROTATE_SPEED | 需程序改代码 |
| 引擎对速度的贡献/重船惩罚 | 船 prefab 上的 ShipEngineBinding 组件 |
_powerPerEngine、_massPenaltyMidpoint、_massPenaltyStiffness |
Inspector 可改 |
| 船长缺岗惩罚力度 | CaptaincyConsts.cs |
MissingMultiplier(0.5)、MissingThoughtDelaySeconds(60) |
需程序改代码 |
| 自动导航到达/卡住判定 | ShipNavigationController.cs 常量 |
ArrivalRadius(5)、StuckTimeWindow(5)、StuckPositionEpsilon(1) | 需程序改代码 |
| 甲板层数/网格大小 | mvp_002 场景 GridManager |
xCount/zCount/minDeck/maxDeck/gridSize |
影响寻路网格规模与初始化耗时 |
本系统没有任何 CSV 配置表;所有数值都在 ScriptableObject 资产、prefab/场景序列化字段或代码常量中。
已知限制与注意事项
Section titled “已知限制与注意事项”- “分层寻路已禁用”记录已过时:项目 CLAUDE.md Known Issues 与
HierarchicalAStarV2PlayModeTests.cs中的注释均指向旧实现;当前代码(2026-05-10 重构后)跨 Cluster 分层寻路已启用且直接返回网格坐标。真实遗留问题是“跨 Cluster + 旋转船体”回归测试被 [Ignore],该场景无自动化测试覆盖。 - 两个失效配置项:
PathfindingConfig.asset的stoppingDistance(0.3)被读取但从未参与任何判定;pathCacheTime(3 秒)完全无人引用——路径缓存实际上永不过期,只按数量上限淘汰。调这两个值不会有任何效果。 - 设计文档与实现的数值差异:设计文档(Docs/Notion/设计/基础系统/寻路系统)写“默认移动速度 5”,实际资产值为 3.3;文档中“停止距离 0.3 用于到达终点判定”未实现(到达判定只用航点距离 0.5)。
- 楼梯识别双标准:可走性判定用“名称包含 stair/ladder/楼梯/梯子”,垂直连接建立用精确名称名单。名称含 stair 但不在精确名单内的建筑(如假想的 “Staircase”)会被当成可走地面却不产生跨层通道。新增楼梯类建筑时两处都要核对。
- 无船员互相避让:寻路不考虑其他船员占位,多名船员可重叠穿行;设计文档“待细化”列表也确认多 Agent 避障未做。
- 无部分路径:目标不可达时直接失败,不会“走到最近可达点”(终点 5 格螺旋修正是唯一的容错,且仅同层)。
- 静默改道:终点不可走时自动改到 5 格内最近可走点,玩家与任务系统都不会收到“目标被替换”的提示。
- 施工中设施即阻挡:设施蓝图一落地(Frame 状态)就阻挡寻路,而地板必须完工才可走——两个层级对“未完工”的处理方向相反,铺设大量蓝图时可能提前堵死通道。
- 键位注释过时:
MovementController.cs多处注释写 WASD,实际输入绑定是方向键(MovementInputActions.cs)。 - 船员速度无状态修正:受伤、饥饿、负重、心情都不影响走路速度(MVP 简化);唯一的全局缩放是游戏倍速。
- 复杂度热点:
PathfindingGrid.cs(约 960 行)被项目标记为谨慎修改区;改动可走性/网关逻辑前建议先跑PathfindingSystem/Tests下的 PlayMode 测试。 - 每艘船一套寻路:AI 船拥有独立的网格/管理器/动态更新器实例;跨船寻路(如接舷登船走格子)不在当前系统能力范围内。