关于 navigation
navigation 是使用 navcat 生成导航网格并查询 3D 环境路径的技能。它指导游戏开发者提取几何体、查询路径和处理群体移动,并说明静态网格限制及随版本变化的 API。
主要功能
- 01从几何体生成导航网格
- 02生成单区或分块网格
- 03查询路径和可行走点
- 04检查表面视线
- 05沿路径移动 Agent
- 06群体寻路与避让
适用场景
- 01让游戏角色绕过障碍物
- 02查找巡逻或漫游目的地
- 03协调成群移动的 Agent
- 04地形变化后重建导航
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ drawcall-ai/ skills --skill navigation安装后在 Claude Code 中输入/navigation确认已加载。
详细介绍
使用 navcat 进行导航
navcat 根据原始几何体构建导航网格(关卡中相互连通、可供行走的多边形),并在其上处理寻路查询。当你需要让某个对象在世界中智能移动时,就可以使用它——例如让敌人绕过障碍物、让 NPC 巡逻、命令单位前往某个位置,或让 Agent 避开墙壁和空隙。它与渲染无关;navcat/three 可将其适配到 Three.js。
你真的需要导航网格吗?对于“在开阔平坦的地面上直奔目标”这种情况,导航网格有些大材小用——直接转向目标即可。当 Agent 必须绕过障碍物、穿越不平坦或多层地形,或作为协同人群移动时,导航网格才有用。如果你的场景更简单,自行实现转向逻辑才是正确选择。
版本会变化——请查看已安装的类型
本指南会帮你选择合适的功能和方案;它不会固定具体签名,因为 navcat 的 API(导出名称、选项字段、返回值结构)会随版本变化。在调用之前,请查看已安装软件包的导出和类型(navcat、navcat/blocks、navcat/three),确认当前的名称和字段。请将以下代码视为结构示例,而非接口约定。
流程概览
- 提取几何体——使用
navcat/three中的getPositionsAndIndices(meshes),将可行走的 Three.js 网格(地面、地形、障碍物)转换为positions/indices。 - 生成导航网格——单个区域(默认情况)调用一次
navcat/blocks中的generateSoloNavMesh(input, options);对于大型世界和局部重建,则使用generateTiledNavMesh。 - 查询——在生成的导航网格上查询路径、最近的可行走点、随机点和视线。
- 移动 Agent——每帧自行沿路径移动,或者将多个 Agent 交给
crowd模块处理。
import { findPath, DEFAULT_QUERY_FILTER } from 'navcat'
import { generateSoloNavMesh } from 'navcat/blocks'
import { getPositionsAndIndices, createNavMeshHelper } from 'navcat/three'
const [positions, indices] = getPositionsAndIndices([floor, ...obstacles])
const { navMesh } = generateSoloNavMesh({ positions, indices }, options) // see options below
scene.add(createNavMeshHelper(navMesh).object) // debug: see the walkable surface
const result = findPath(navMesh, start, end, halfExtents, DEFAULT_QUERY_FILTER)
const waypoints = result.path.map((p) => p.position) // [x,y,z][]
halfExtents 是用于将 start/end 吸附到网格上的搜索框;如果查询失败,说明你的点可能不在导航网格上——请扩大搜索框,或先通过最近多边形查询进行吸附。
调整生成参数
生成选项会根据 Agent 的尺寸确定导航网格,并在细节与速度之间进行权衡。你无需记住所有字段(请从已安装的 SoloNavMeshOptions 中查看);只需理解几个重要参数即可:
- Agent 尺寸——可行走的半径(与墙壁保持的间距)、高度(排除低矮天花板)、攀爬高度(可跨越的最大台阶高度),以及最大可行走的坡度角。请根据角色设置这些参数。
- 分辨率——单元格的宽度/高度(体素网格):越小越精细,但速度越慢。常见的起始设置是单元格宽度 ≈ Agent 半径 / 3。
- 简化——区域、边缘和误差限制决定生成的多边形会有多方正或平滑。
如需自定义单个生成阶段(标记区域、注入区域),navcat 还提供了更底层、类似 recast 的步骤,一次性生成器正是基于这些步骤构建的。只有当生成器无法满足需求时,才使用这些步骤。
查询导航网格
所有查询都需要导航网格和查询过滤器(除非标记区域代价/标志,否则使用 DEFAULT_QUERY_FILTER)。可用于寻路的功能包括:
findPath— 返回两点之间的完整路径,以路点表示。沿表面生成无转角路径可使用findSmoothPath。(对于缓存或动态移动,节点路径与直线路径这对功能可提供更精细的控制。)- 最近的可行走点 — 将世界位置吸附到网格上;这是判断“此处是否可达”和修复查询失败的基础。
- 随机可行走点(任意位置,或中心点周围一定半径内)— 用于生成点、巡逻目的地和漫游目标。
- 沿表面执行
raycast— 检查网格上两点之间的视线。注意无命中约定:射线畅通时,返回的命中参数是该软件包表示“无墙”的哨兵值(一个最大值,而非1.0或0)——请在已安装的类型定义中确认,切勿想当然。 moveAlongSurface— 在保持于可行走区域内的同时,将位置朝目标滑动;无需完整重新寻路的简单控制方式。- 离网连接 — 跨越网格无法连接的间隙的显式链接(跳跃、梯子、传送)。
每帧沿路径移动
findPath 会返回路点;如何移动 Agent 是由你的循环负责的。朝当前路点移动,抵达后前进到下一个路点;目标改变或 Agent 偏离路径时,重新寻路:
let waypoints = result.path.map((p) => p.position)
let i = 0
function updateAgent(pos, speed, delta) {
if (i >= waypoints.length) return // arrived
const t = waypoints[i]
const dx = t[0] - pos[0], dz = t[2] - pos[2]
const dist = Math.hypot(dx, dz)
if (dist < 0.2) { i++; return }
pos[0] += (dx / dist) * speed * delta
pos[2] += (dz / dist) * speed * delta
}
多个 Agent → crowd 模块
对于群体(敌人蜂拥而至、单位集体移动),请使用 navcat/blocks 中的 crowd API,而不是手动沿路径跟随——它会帮你处理分帧寻路、Agent 间避和墙壁避障,以及保持间距。避免让群体挤成重叠的一团:
- 为每个 Agent 设置与其身体尺寸相符的半径,并让避障功能保持间距。不要每帧都手动将所有 Agent 的速度直接设为朝向同一个点——这会覆盖避障效果,让它们叠在一起。
- 若要围攻目标,为每个 Agent 设置一个位于目标周围环形区域上的偏移量(根据索引/角度分散),让它们包围目标,而不是争抢中心位置。
- 调整避障强度和最大加速度,让 Agent 能相互绕行,而不是抖动或互相穿透。
如有高级需求,可将 crowd 模块复制到项目中并进行修改。
限制 — 知道何时需要自行补足
- 导航网格是静态的。 它反映的是生成时的几何形状。可行走几何发生变化时(例如门打开、地形变形),你必须重新生成——
generateSoloNavMesh会重建整个区域;分块导航网格则只重建受影响的区块。对于少量移动障碍物,在导航网格上叠加你自己的局部转向/避障逻辑,通常比不断重建更省资源。 - 约定: navcat 遵循 OpenGL 约定(右手系、逆时针绕序)。如果你的数据不同,请在输入和输出时转换坐标。导入的外部导航网格必须让相邻多边形共享/索引相同的顶点。
- 确保碰撞几何与导航网格都贴合同一形状的地形——不要在起伏的地面下方使用平坦地板(参见
world技能),否则 Agent 会穿过可见的山丘寻路。 - 导航网格是普通 JSON——将生成的导航网格序列化后保存,可在加载时跳过重新生成。