mcpField
G
godot-game-loop-waves

godot-game-loop-waves

github.com/thedivergentai开发907292 次安装2 周前更新
代码仓库

关于 godot-game-loop-waves

面向 Godot 开发者的波次游戏循环技能,介绍以 WaveResource 配置遭遇内容、由管理器编排生成和通关判定的架构,并按敌人规模选择节点或服务器端方案。

主要功能

  1. 01WaveResource 驱动遭遇配置
  2. 02管理器处理波次时序与胜利判定
  3. 03Marker 与加权生成器提供生成位置
  4. 04按密度选择节点、MultiMesh 或 RID 方案
  5. 05提供对象池、异步寻路等模式

适用场景

  1. 01搭建线性关卡的敌人波次
  2. 02制作按难度倍率递增的无尽模式
  3. 03实现玩家进入 Area3D 后触发遭遇
  4. 04为大规模敌群选择合适的生成架构

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/thedivergentai/game-dev-agentic-skills --skill godot-game-loop-waves

安装后在 Claude Code 中输入/godot-game-loop-waves确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
migration-notes.md
wave-expert-patterns.md
scripts/
wave_loop_patterns.gd
wave_manager.gd
wave_resource.gd
wave_spawner.gd
wave_weighted_spawner.gd

详细介绍

架构设计: “Wave-State”模式

成熟的实现会将波次视为数据驱动的转换。不要硬编码生成数量,而是使用 WaveResource 定义“遭遇”,并由 WaveManager 按顺序处理。

核心职责
  • 管理器:编排时间线,处理波次间的延迟,并跟踪“胜利”条件(所有敌人均已死亡)。
  • 生成器:解耦的节点,为敌人出现的位置提供空间信息(wave_spawner.gd / wave_weighted_spawner.gd)。
  • 资源:不可变的数据容器,让设计师无需修改代码即可重新平衡游戏。

密度决策树(编码前选择规模)

实时密度方案必须加载
约 80 个以下的 SceneTree 敌人节点管理器 + Marker 生成器wave_manager.gd、wave_spawner.gd、wave_resource.gd
群集视觉效果 / 数百个MultiMesh + 加权组合wave_loop_patterns.gd(MultiMesh / 异步路径)、wave_weighted_spawner.gd
约 10k 个物体PhysicsServer / NavigationServer RIDs(每个小怪不创建 Node)wave_loop_patterns.gd 中的服务器 RID 模式;不要扩展 wave_manager 节点生成

wave_manager.gd 是 SceneTree 的推荐路径(延迟执行 add_child、通过组/信号统计清除数量、可选对象池)。将其视为原型→中等规模方案——对于 RID 群集,请遵循 wave_loop_patterns.gd,而不是实例化数千个节点。

组合推荐路径

  1. 编写 wave_resource.gd 组合表。
  2. 放置 wave_spawner.gd Marker(需要权重控制多样性时,使用 wave_weighted_spawner.gd)。
  3. 将 wave_manager.gd 的 spawner 指向该 Marker;管理器会延迟生成,并通过 &"enemies" 组 + 信号清除敌人。
  4. 使用权重替代固定数量时,在组合循环中调用 WaveWeightedSpawner.spawn_enemy()(或将管理器的 spawner 设置为加权节点)。

专家级代码模式

1. 异步波次触发

在 wave_manager.gd 中使用 await 计时器——编写自定义时间线前必须阅读。生成时使用 call_deferred(&"add_child", …);通过信号/组(而非扫描 get_children())清除敌人。

2. 基于组合的生成

在 wave_resource.gd 中定义多样性;使用 wave_spawner.gd / wave_weighted_spawner.gd 放置单位。不要在管理器中硬编码场景路径。

专家级决策矩阵:进程

模式最适用于逻辑
线性剧情任务手工编写的 WaveResource 列表。
无尽生存模式使用倍率计算生成的 WaveResource。
触发式RPG 遭遇仅当玩家进入 Area3D 时才开始波次。

绝对不要做

  • 绝对不要遍历 get_children() 来查找所有敌人 — 这非常慢。务必将敌人添加到 "enemies" 组,并使用 get_tree().get_nodes_in_group(&"enemies") 高效访问。
  • 绝对不要频繁实例化和释放数百个敌人 — 这会导致垃圾回收卡顿。使用对象池复用现有敌人实例。
  • 绝对不要为蜂群生成数千个独立的 MeshInstance3D 节点 — 这会严重拖累绘制调用。使用 MultiMeshInstance3D 将数千个网格合并为一次 GPU 调用。
  • 绝对不要在主线程上为数百个 Agent 计算寻路 — 这会让游戏卡死。为导航区域启用 use_async_iterations,或使用 NavigationServer3D.query_path()。
  • 绝对不要忘记在添加子节点前检查 is_inside_tree() — 如果生成器已排队等待删除,添加子节点会导致崩溃。务必确认生成器仍处于场景树中。
  • 绝对不要将预加载的资源(例如 stats.tres)直接赋给生成的敌人 — 它们会共享完全相同的生命值和属性。务必调用 base_stats.duplicate_deep(),为每个敌人提供独立数据。
  • 绝对不要在高频组调用中使用标准字符串 — 务必使用 StringName(&"enemies"、&"take_damage"),以获得最佳哈希性能并避免不必要的字符串分配。
  • 绝对不要在物理回调中同步直接生成实体 — 在物理步骤期间实例化节点可能会破坏物理状态。务必使用 call_deferred(&"add_child", enemy)。
  • 绝对不要让死亡敌人的 CollisionShapes 继续处于启用状态 — 尸体会阻挡防御塔和导航。死亡时立即使用 set_deferred("disabled", true)。
  • 绝对不要通过 MultiplayerSynchronizer 同步复杂的 Object 类型 — 它只支持基本类型。对于复杂数据,请同步 UID 或 ID,并在客户端本地查找数据。
  • 绝对不要在没有向玩家提供反馈的情况下自动开始波次 — 务必提供 UI 倒计时、可视化的“波次即将来袭”效果或开始按钮,让玩家保有自主权。
  • 绝对不要将生成位置硬编码为 (0,0,0) — 在编辑器中使用 Marker3D 节点,这样无需翻查代码即可直观地调整生成点。
  • 绝对不要每帧通过统计子节点来检查波次是否完成 — 这样开销太大。维护本地计数器,或使用基于信号的系统来追踪活跃敌人数量。
  • 绝对不要让所有实体类型使用同一个导航地图 — 如果同时有飞行和步行敌人,请使用独立的导航地图,避免寻路问题。
  • 绝对不要为生成器的碰撞形状使用非等比缩放 — 这会破坏碰撞检测计算。请改为调整形状资源属性。

可用脚本

必读:实现相应模式前,先阅读对应脚本。

wave_loop_patterns.gd

10 种专家模式:MultiMesh 蜂群、异步寻路、后台预加载和服务器端物理敌人。

wave_manager.gd

负责协调时间线、波次间延迟,并通过组计数和信号追踪清场情况。使用 call_deferred 调用 add_child;可通过 use_pool / recycle_enemy 选择启用对象池。

wave_resource.gd

用于存储波次组成和难度设置的数据容器。

wave_spawner.gd

Marker3D 空间传送门——使用 get_spawn_position() 获取生成位置,并可选加入半径抖动。将其设置为 WaveManager.spawner。

wave_weighted_spawner.gd

在 Marker 处按权重随机选择敌人。当组成多样性由概率决定,而非固定数量时使用。


专家级波次模式

1. 群体遮挡剔除

为了优化数百个敌人同时出现时的性能,请启用遮挡剔除。

  • 设置:在竞技场中添加一个 OccluderInstance3D 并烘焙。
  • 效果:完全被墙壁或柱子遮挡的敌人不会交由 GPU 处理,从而显著提升 FPS。
2. 波次 UI 架构

使用 CanvasLayer 和信号,将波次数据与 UI 解耦。

  • 波次计数器:显示当前波次和总波次。
  • 生命值条:对于 Boss,可在 CanvasLayer 上使用 TextureProgressBar;对于单个敌人的生命值条,可使用带视口纹理的 Sprite3D。

按需获取专家知识

**大模型无知规则:**如果通用 Agent 在阅读前不会知道某项内容,就加载参考资料——绝不要删除专家增量内容。

参考资料

渐进式披露:仅在研究特定 API 时打开官方文档链接;在路由到相关领域时加载相关技能——不要预加载整个技能网络。

官方文档
  • 资源 — WaveResource 组合和延迟可由设计人员编辑,无需在管理器中硬编码生成表。
  • 节点和场景实例 — 对于波次敌人,使用 PackedScene.instantiate() 加上 add_child / call_deferred 是安全的生成方式。
  • 组 — 使用 StringName 组和 get_node_count_in_group 跟踪存活的怪物,而不是每帧扫描子节点。
  • 空闲与物理处理 — 使用计时器和 await 控制节奏;不要在物理回调中实例化对象而不延迟处理。
  • SceneTreeTimer — 使用 create_timer 设置波次前延迟和生成间隔,无需使用永远运行的 _process 倒计时。
  • 使用信号 — wave_started / wave_cleared / all_waves_complete 可让 UI、音频和战斗系统与管理器的时间线解耦。
  • 后台加载 — 使用 ResourceLoader.load_threaded_request 加载 Boss 或大型波次,避免首次生成时卡顿。
  • 随机数生成 — 使用 RandomNumberGenerator.rand_weighted 实现加权组合和生成位置抖动。
  • 使用 MultiMesh — 当数百个小怪导致绘制调用激增时,批处理群体的视觉效果。
  • 遮挡剔除 — 隐藏竞技场中不在镜头内的怪物,让密集波次的 GPU 开销保持在可控范围内。
  • 导航简介(3D) — 为飞行和行走的波次单位使用异步 Agent 路径和独立导航地图。
  • 使用服务器 — 当 SceneTree 节点无法扩展时,使用 PhysicsServer3D/NavigationServer3D RID 处理群体。
相关技能
前置要求
补充内容
下游 / 使用方
主入口
  • godot-master — 用于跨技能发现的库路由器和镜像模块入口。

评论

支持 Markdown