今日速览

  • Godot 寻路有三套方案:AStar2D(自定义点图)、AstarGrid2D(网格地图)和 NavigationServer2D(导航网格,适合自由移动的实时玩法),选错方案会事倍功半。
  • 最小可用流程只需 3 步:加 NavigationRegion2D → 画 NavigationPolygon 并 Bake → 角色下挂 NavigationAgent2D 写移动脚本。
  • 核心 API 只有 4 个:target_position(设目标)、get_next_path_position()(取下一个路径点)、is_navigation_finished()(判断到达)、外加两个距离参数调手感。
  • 经典坑:第一帧地图还没同步,直接查路径会返回空;敌人”跳舞/来回踱步”通常是每帧都重算路径导致的。
  • 避障(Avoidance)与寻路是两套独立系统:避障只负责”别撞到移动中的同类”,静态障碍物必须靠烘焙进导航网格解决。

核心学习内容

1. 先选对工具:三种寻路方案怎么挑

Godot 官方文档把 2D 寻路分成三类,对应不同游戏形态:

  • AStar2D:自己定义”点 + 连线 + 权重”的图,适合只有固定几个关键位置的玩法(如棋盘、传送点)。
  • AstarGrid2D:网格地图专用,不需要手动建点连线,给格子设通行/阻挡即可。地牢、俯视角网格类游戏首选,还能复用你的 TileMap 数据。
  • NavigationServer2D(导航网格):用多边形面片(NavigationPolygon)定义”可站立区域”,角色可以到达区域内任意位置。横版动作、自由移动的 ARPG 首选,一大片空地只需一个多边形,大型地图性能更好,也是今天的主角。

2. 场景搭建:3 步让敌人学会绕路

以官方 “2D Navigation Polygon” 演示为蓝本:

  1. 场景根节点下加 NavigationRegion2D,选中后在检查器新建 NavigationPolygon 资源。
  2. 用工具栏的绘制工具圈出”敌人能走的区域”(围墙、坑洞不要圈进去),点击 Bake NavigationPolygon 烘焙。⚠️ 官方特别提醒:导航多边形边缘要离碰撞体留出余量,否则角色会卡在墙边反复蹭。
  3. 给敌人 CharacterBody2D 加一个子节点 NavigationAgent2D,挂脚本。

3. 追击脚本:4 个 API 组成的核心循环

extends CharacterBody2D

@export var movement_speed: float = 150.0
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D

func _ready():
    # 距离参数要按角色速度和关卡尺度调
    nav_agent.path_desired_distance = 4.0
    nav_agent.target_desired_distance = 4.0
    actor_setup.call_deferred()

func actor_setup():
    # 关键:等一个物理帧,让 NavigationServer 完成地图同步
    await get_tree().physics_frame
    nav_agent.target_position = get_node("../Player").global_position

func _physics_process(_delta):
    if nav_agent.is_navigation_finished():
        return  # 到达目标,别再查路径,否则原地抖动
    var next_pos: Vector2 = nav_agent.get_next_path_position()
    velocity = global_position.direction_to(next_pos) * movement_speed
    move_and_slide()

要点拆解:

  • target_position 一旦设置,寻路自动开始,路径由 get_next_path_position() 逐个吐出(导航系统不会替你移动角色,移动永远是你的代码负责)。
  • path_desired_distance:离下一个路径点多近就切换到下一点;target_desired_distance:离终点多近算”到达”。角色速度快就把这两个值调大,否则会”跑过头又折返”。
  • 追击类敌人可以每 0.3~0.5 秒更新一次 target_position(用 Timer 或帧计数),既省性能又避免”被玩家甩开后原地抽搐”。

4. 进阶:多敌人避障与常见坑排查

多个敌人追同一个玩家会互相叠在一起,此时开启避障:勾选 NavigationAgent2D 的 avoidance_enabled,连接 velocity_computed 信号,在 _physics_process 里把期望速度喂给 set_velocity(),然后用信号回调里的 safe_velocity 移动。相关调参:radius(角色体型)、neighbor_distance(只避多近的邻居)、max_speed。

官方文档列了 4 个高频问题,值得背下来:

  1. 路径返回空 → 地图还没同步,用 call_deferred + await physics_frame 解决(或检查 NavigationServer2D.map_get_iteration_id() 是否为 0)。
  2. 在两个点之间跳舞 → 每帧都在重算路径,检查是否把 target_position 更新放进了 _physics_process 且无间隔。
  3. 偶尔折返/回头看一眼 → 跑太快超过了判定距离,调大两个 desired distance,或让导航多边形别太碎。
  4. 避障没生效 → 避障只对”同样开启避障的 agent”生效,且必须设置了 target_position 才会输出 safe_velocity。

🎯 DeepSeek 提示词

提示词 1:生成完整的敌人追击 AI 脚本

适用场景:不想手写样板代码,直接让 DeepSeek 产出可用的追击敌人。

你是资深 Godot 4 游戏开发者。请为我的 2D 横版动作游戏写一个"近战敌人追击 AI"的 GDScript 脚本。
要求:
1. 节点结构:CharacterBody2D(敌人)下挂 NavigationAgent2D 子节点,另有一个 Area2D 作为近战攻击范围检测。
2. 行为:玩家进入 detection_range 后开始追击;距离小于 attack_range 时停止移动并攻击;玩家离开 detection_range 超过 3 秒后停止追击,回到巡逻点。
3. 追击用 NavigationAgent2D 寻路,记得处理"第一帧地图未同步"问题(用 call_deferred + await physics_frame)。
4. 目标位置每 0.4 秒刷新一次,避免每帧重算。
5. 导出变量:movement_speed、detection_range、attack_range、attack_cooldown,均可 @export。
6. 输出格式:先给完整脚本(带中文注释),再列 3 条"接入步骤"(场景里怎么搭节点、参数怎么设),最后列出 2 个最容易出错的点。
请直接给出代码,不要解释太多理论。

使用说明:跑出来的脚本如果报错,把报错原文粘回给 DeepSeek 让它修;接入时记得先有 Player 节点(脚本里引用了它的 global_position)。

提示词 2:寻路 Bug 诊断模板

适用场景:敌人表现诡异(抖动、折返、卡墙),把现象贴给 DeepSeek 做”医生”。

你是 Godot 4 寻路系统专家。我的敌人用 NavigationAgent2D 追击玩家时出现以下症状:
【症状】角色在两个相邻位置之间来回抖动,像在"跳舞",偶尔还会回头看向身后。
【我的配置】movement_speed=300(角色跑得很快);path_desired_distance=4.0;target_desired_distance=4.0;我在 _physics_process 里每帧都更新 nav_agent.target_position = player.global_position。
【完整脚本】(粘贴你的敌人脚本)
请按可能性从高到低列出原因,并针对每一条给出具体的修复代码。最后直接给我一份修改后的完整脚本。如果怀疑是配置问题而不是代码问题,请明确告诉我该改哪个属性的值、改成多少、为什么。

使用说明:这是个可复用的”症状→诊断→修复”模板。把【症状】【配置】【脚本】三段替换成你的实际情况即可,适合所有寻路异常(空路径、折返、避障失效都能套)。

提示词 3:网格地图换 AstarGrid2D 方案

适用场景:如果你的游戏是地牢/网格地图,别用 NavigationRegion2D,让 DeepSeek 直接改写。

你是 Godot 4 游戏开发者。我的地牢游戏用的是 TileMapLayer 搭的地图,现在要写"怪物从出生点寻路到玩家"的逻辑。
约束与要求:
1. 使用 AstarGrid2D(不要用 NavigationAgent2D/NavigationRegion2D),因为地图是格子的。
2. 基于已有 TileMapLayer 自动生成网格:遍历 tile 坐标,把"可行走格子"加入 AstarGrid2D(用 set_point_solid 或相应 API 标记阻挡格)。
3. 提供两个函数:update_navigation()(地图变化时重算)和 get_path(from_cell: Vector2i, to_cell: Vector2i) -> Array[Vector2i](返回路径格子序列)。
4. 怪物按路径移动时用 move_toward 平滑插值,不做瞬移;寻路失败(无路可达)时返回空数组并打印警告。
5. 输出:完整 GDScript(含中文注释)+ 一段示例调用代码(怪物 _physics_process 里怎么用)。
注意:请使用 Godot 4.x 的 AstarGrid2D API,不要用 Godot 3 的旧写法。

使用说明:地牢/棋盘类游戏用 AstarGrid2D 更省;拿到代码后重点核对 API 名(Godot 4 是 AstarGrid2D,别让 AI 写成 3.x 的 AStar2D 手动建点版本)。

学习心得

距离”用 DeepSeek 做出可上架 Steam 的游戏”又近了一步:敌人只会直线冲脸的游戏,玩家玩 10 分钟就会腻;会绕路、会包抄、会从侧门堵你的敌人,才撑得起”好玩”二字。今天这套 NavigationRegion2D + NavigationAgent2D 是 Godot 所有”会移动的 AI”(敌人、NPC、宠物)的地基,而且样板代码高度模板化——正是 DeepSeek 最擅长的场景:把今天的提示词 1 存好,以后每个新敌人类型(远程兵、BOSS)都能在 30 秒内生成一个可跑的追击脚本,再花时间只调”性格参数”(速度、索敌距离、攻击节奏),这才是 AI 辅助开发的正确姿势:AI 写骨架,人调灵魂。

明日关注

  • 复习避障参数(radius / neighbor_distance / max_speed)与 velocity_computed 信号回调的接线方式,做一个小场景实测多敌人追击
  • 把今天 3 条提示词存进自己的”DeepSeek 提示词库”,补一条”让敌人沿路径做简单巡逻(走 A→B→A 折返)“的变体
  • 对照自己的游戏原型:当前地图是自由移动还是网格制?据此确定该用 NavigationServer2D 还是 AstarGrid2D

本文由自动化学习流水线每日生成,坚持即学即记。