mcpField
S
scenario-godot-gameplay

scenario-godot-gameplay

github.com/scenario-labs开发1.2k158 次安装1 天前更新
代码仓库

关于 scenario-godot-gameplay

面向 Godot 4.7.2 的 gameplay 系统编程技能,供构建导航、AI、战斗、对话和程序化内容的开发者使用。它强调用无场景决策逻辑、数据定义和可测量的基准验证系统。

主要功能

  1. 01导航网格构建与同步
  2. 02基于规模选择 AI 方案
  3. 03碰撞、命中框与子弹设计
  4. 04存档验证和版本迁移
  5. 05对话、任务及程序化内容流程

适用场景

  1. 01测量不同规模敌群的帧耗
  2. 02验证 NavigationAgent3D 移动
  3. 03测试命中检测与高速子弹
  4. 04检查存档、对话和地牢生成

MCP 相关

此技能要求 scenario-godot-expert 背景;输入说明未指出它自身提供 MCP 服务或客户端功能。

安装

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

$npx skills add https://github.com/scenario-labs/skills --skill scenario-godot-gameplay

安装后在 Claude Code 中输入/scenario-godot-gameplay确认已加载。

包含的文件

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

references/
critique.md
expert-notes.md
gui-paths.md
procedures.md
sources.md
scripts/agentkit/gameplay/
arena.gd
brain.gd
bullet_pool.gd
combat_layers.gd
crowd_bench.gd
dungeon_gen.gd
enemy_body.gd
enemy_manager.gd
hero_enemy.gd
hit_log.gd
hitbox_3d.gd
hurtbox_3d.gd
nav_tools.gd
perception.gd
quest_rules.gd
save_io.gd
state_machine.gd
state.gd
scripts/agentkit/gameplay/inventory/
inventory.gd
item_stack.gd
item.gd
scripts/agentkit/gameplay/states/
attack.gd
chase.gd
patrol.gd
search.gd

详细介绍

Godot 游戏玩法系统(游戏玩法系统程序员)

目标:Godot 4.7.2.stable、Jolt、macOS Apple Silicon。

在专家级实践中,游戏玩法系统是无需场景即可测试的小型契约:纯决策函数、用于数据的 Resources、用于发现的组。它们的成本应按游戏实际需要的 Agent 数量衡量,而不是等到有人质疑时才讨论。核心做法:将规则构建为数据,在 --fixed-fps 60 下无头运行,然后查看一张截图。如果此处提到的同级技能不在你可用的技能中,请让用户安装它 (npx skills add scenario-labs/skills --skill <name>);如果无人值守,则根据工具架构继续操作,并标明这一缺口。

必备背景: scenario-godot-expert(channels、gd_run、审查循环、4.7 陷阱)。

状态(2026-10-02): 16 项实时测试、第二轮检查(P15)和离线套件均已在 Godot 4.7.2 中通过(references/procedures.md、tests/code/godot-gameplay/)。 Dialogue Manager 4.1.0、LimboAI 1.8.1 和 GUT 9.7.1 均在各自的项目副本中运行过。

做法(专家级要点)

  1. 使用 --fixed-fps 60 进行基准测试,绝不使用普通无头模式。 无头帧会休眠 6.9 ms (low_processor_usage_mode_sleep_usec),物理帧数少于渲染帧数。 Performance.TIME_* 监视器大约每秒刷新一次,在固定帧率下读数为 0。测量每帧实际耗时(毫秒),取 3 次测量的中位数,并比较同一次运行中的 A/B 配对结果(实测,P0)。
  2. 人群规模并非基准测试所认为的瓶颈。 在 M5 Max 上,200 个启用了 NavigationAgent3D 避让的 CharacterBody3D 敌人每帧耗时约 2 ms。成本随数量线性增长,800 个 Agent 时为 7.3 ms;200 个 Agent 时,避让本身的成本处于噪声范围内。调整 max_neighbors 或重新寻路间隔没有带来可测的收益。避让的价值在于正确性:启用时没有重叠对象对,不启用时则有 3108 对(P2)。只有当 Agent 不需要节点时,才改用服务端 Agent 加一个 MultiMesh(200 个耗时 0.26 ms)。
  3. 等待你分配的网格,而不是等待“地图”。 文档说等待一个物理帧。实际运行中,首次同步耗时 3 帧。重新烘焙后,地图 ID 已改变,但区域仍提供旧多边形。分配前读取 region_get_iteration_id,等待其变化,然后再进行一次地图同步(nav_tools.wait_applied,P1)。
  4. 从静态碰撞体组烘焙。 新建的 NavigationMesh 会从区域的子节点解析 Both(网格和碰撞体),因此放在区域下的 NPC 会挖出一个 3 m 的空洞(Bramwell 2W4JP48oZ8U 00:12:37;P1 实测)。
  5. 根据决策条件选择 AI 档位。 人群使用枚举式大脑(Shaggy Dev oqFbZoA2lnU 00:00:32),英雄或玩家角色使用节点 FSM。设计师编写行为时使用行为树(Chap.C E_FIy2dTkNc);只有在许多通用动作会重新组合时才使用 GOAP(Wahaha Yes cm5Jxo31plw)。预算参考:每个 tick 处理 40 个敌人、以 5 Hz 运行,耗时比不运行 AI 高 0.07 ms;每个 tick 处理所有敌人则高 0.45 ms(P3)。
  6. Hitbox 使用 mask,Hurtbox 使用 layer,每次挥击使用一个 HitLog(Queble cX-vzfmzjnE 00:06:36、00:12:55)。 新建的区域默认 layer 为 1、mask 为 1,因此会命中自身所属对象(P4)。
  7. 快速子弹应使用数据,或使用启用了 CCD 的刚体。 不启用 continuous_cd 时,即使速度达到 30 m/s,8 个球中仍有 6 个穿过了 0.1 m 厚的墙。Jolt 会将速度限制在 500 m/s。由一个 MultiMesh 绘制的射线扫掠式数据子弹,每 1000 发耗时 0.35 ms;使用 CCD 的池化 RigidBody3D 则耗时 1.05 ms(P5)。
  8. .tres 存档就是代码。 GDScript 子资源会在加载时运行(Godotneers 43BZsLZheA4 01:03:14;P6 已复现)。加载前先扫描,使用 CACHE_MODE_IGNORE 加载,进行版本管理和迁移,并验证数值,而不是加密(01:01:37)。

NavigationAgent3D 约定(P15,实测)

文档警告(NavigationAgents 页面)和 Bramwell(2W4JP48oZ8U 00:14:14),除非另有标注,均在 4.7.2 中实测:

  • 避障需要 target_position。 开启避障但没有目标时,safe_velocity 连续 30 个 tick 都保持为 0;有目标时则返回完整的 3 m/s。
  • 避障不会影响寻路。 Agent 是圆形,不了解导航网格或物理信息,因此墙壁仍需由路径处理(文档)。
  • 每个物理帧调用一次 get_next_path_position(),到达终点后不再调用。 is_navigation_finished() 为 true 后,它仍会返回最后一个点(这里相距 0.93 m):此时应停止转向,否则 Agent 会缓慢爬行。
  • path_desired_distance 必须大于一个 tick 的移动距离,以及导航网格高出地面的浮点误差(约 0.3 m)。 以 25 m/s(每个 tick 移动 0.42 m)移动并将其设为 0.1 时,Agent 在 1800 个 tick 中有 1782 个 tick 向后移动,始终未能到达;设为 1.0 时则在 182 个 tick 后到达。设为 0.1 且脚部测得与地面齐平时,Agent 始终无法离开第一个路径点。
  • 默认值: time_horizon_agents 为 1.0,time_horizon_obstacles 为 0.0。如果 Agent 过早减速,请缩短时间范围。max_neighbors 太小会导致避障被忽略(文档;此处未实测)。

首先确定

输入对计划的影响默认值
屏幕上的 Agent 数量使用节点还是服务器 Agent、思考预算200
游戏玩法的帧预算每项基准测试的门槛60 fps 时为 16.67 ms 的四分之一(4.2 ms)[已添加]
2D 还是 3DNavigationAgent2D 还是 3D、Area2D 还是 3D3D
谁负责编写行为代码(FSM、枚举)还是设计师(LimboAI)代码
存档信任度仅自己的文件还是共享或经过模组修改的存档共享:扫描或 JSON
平台输入设备、CPU 预算桌面端、键盘和鼠标及手柄

工作流

  1. 设置项目。
    • 使用 gd_env.base_project("3d", P) 克隆 Base3D,并为其设置独立的 application/config/name, 否则克隆项目会共享 user://。运行 gg.install(P)。
    • GATE:project.godot 中有 3d/physics_engine="Jolt Physics" 和明确指定的渲染器; gd_run.check_all(P) 报告 0 个解析错误。
  2. 关卡导航。
    • 将静态几何体放入组 nav_source。使用 make_navmesh(parsed colliders, source group) 构建网格,然后执行 bake,再执行 wait_applied。
    • GATE:样本点之间的 map_get_path 结果非空,且穿过的障碍物数量为 0;多边形 数量大于 0;NPC 出生点处没有空洞(P1)。
  3. 移动与人群。
    • 启用避障;使用 velocity_computed 驱动 move_and_slide;限制重新寻路的频率;仅沿 XZ 方向转向。
    • 在 50、200 和 800 个对象时运行 gg.crowd_bench(P, n),然后运行 gg.scaling_verdict。在你自己的基准测试场景中,将 Performance.add_custom_monitor(&"ai/thinks", callable) 和 OBJECT_ORPHAN_NODE_COUNT 与运行时间一并记录(创建 5 个多余的 Node.new() 后读数为 5,P15)。
    • GATE:重叠对象对数量为 0;指数低于 1.3;目标数量下的中位数符合游戏预算(gg.budget_share);孤立节点数量保持不变。然后打开人群的窗口化捕获结果。
  4. AI。
    • 使用带滞回的 decide(state, percept) 编写大脑。感知先保持轻量 (距离、视锥、一次射线检测、过期命中检查)。管理器以约 5 Hz 的频率思考,并限制每个周期的处理数量。远处的敌人降低思考频率:根据距离平方划分层级,因为 VisibleOnScreenNotifier3D.is_on_screen() 在无头模式下始终返回 false,基准测试会把所有对象都划入远处层级(P15)。节点 FSM 用于英雄;如果由设计师编写,则使用 LimboAI。
    • GATE:GUT 状态转换表全部通过;英雄场景历史符合预期顺序(巡逻、追击、攻击、追击、搜索、巡逻);已测量思考成本的 A/B 对比(P3、 P9、P13)。
  5. 战斗。
    • 为层命名(World 1、Player 2、Enemy 3、PlayerHurtbox 5、EnemyHurtbox 6、Projectile 7)。 Hitbox 和 hurtbox 使用工具包中的内容。子弹使用 bullet_pool;反弹物体使用带 CCD 的 RigidBody3D。
    • GATE:共享日志记录的一次挥击命中 1 次;同阵营命中 0 次;最高速度下的穿透测试结果为 8 次中 0 次;子弹位于独立层(P4、P5)。
  6. 持久化。
    • 使用带 VERSION 和 migrate() 的类型化保存 Resource、save_io.save_resource_atomic、 load_resource_checked;每个持有者都使用独立副本的库存。
    • GATE:往返结果相等;所有旧版样本文件都能加载;恶意样本文件会被拒绝;缓存测试通过(P6、P7)。
  7. 对话与任务。
    • 使用 Dialogue Manager 4.x 的 .dialogue 文件;任务顺序为交付,然后继续,最后提供。
    • GATE:导入时编译所有文件,且错误数为 0;gg.check_dialogue_text 未发现缺失提示;无头模式下的遍历能到达每个分支并改变状态(P8)。
  8. 输入。
    • 使用物理按键操作;在 _unhandled_input 中处理游戏输入;将按键重新映射保存到 ConfigFile。
    • GATE:合成按键和 just-pressed 测试通过;STOP 面板会接收并处理推送的点击;重新加载后按键映射仍然保留(P10)。
  9. 程序化内容。
    • 先生成带种子的数据(dungeon_gen),再运行验证器,然后生成几何体、烘焙并寻路。
    • GATE:1000 个种子均无验证失败;相同种子生成相同哈希;起点到 Boss 存在路径;已打开顶部捕获结果(P11)。
  10. 收尾。

数值

数值测量结果对比条件
200 个带避障的实体每帧 1.98 ms,0 次重叠M5 Max,固定帧率 60,60 m 竞技场,14 个障碍物
避障时的扩展情况50 个 Agent:1.07 ms,200 个:2.00,800 个:7.31(每个 Agent 约 9 µs)相同
200 个服务端 Agent 加 MultiMesh0.26 ms相同
思考开销,200 个敌人预算 0.40 ms,每个 tick 0.78,不思考时 0.335 Hz,每个 tick 40 个
首次 navmesh 同步3 个物理帧;rebake 在 2 到 16 后应用开启异步迭代(默认)
烘焙5 ms,180 个多边形60 m 竞技场,单元格 0.25
1000 颗子弹数据 0.35 ms;带 CCD 的 RigidBody3D 为 1.05;不带 CCD 为 1.00(45% 未命中墙壁)60 m/s,存活时间 2 s
Jolt 速度上限500 m/sphysics/jolt_physics_3d/limits/max_linear_velocity
地牢生成并验证中位数 88 µs,1000 个中 1000 个有效主路径 14 个房间,4 个分支
NavigationAgent3D 默认值半径 0.5,max_neighbors 10,neighbor_distance 50,max_speed 10,关闭避障4.7.2 ClassDB

质量门槛

  • 可测量:群体指标(重叠对数、最小对间距、卡住、穿过地板); scaling_verdict;budget_share;GUT(gd_run.run_tests)在一次有意失败后通过; check_all 无解析错误;对 1000 个种子运行验证器;保存测试样例;编译对话。
  • 视觉:在 SubViewport 中进行窗口化截图(160x90 窗口),使用 gd_review.image_checks 和 不超过 1600 px 的联系表,并打开查看。检查玩家周围的群体间距、障碍物内部没有 Agent,以及从地牢起点到首领的路径。

常见错误

错误表现修正
基准测试普通无头模式无论负载如何,每“帧”约 7 ms--fixed-fps 60
指定网格后立即查询路径路径为空,Agent 在生成点待机wait_applied
使用默认烘焙(从根节点选择 Both),且内部有 NPC生成点周围出现空洞分组并使用静态碰撞体
为了“提速”关闭避让3108 个重叠对,敌人彼此合并开启避让:200 个对象时开销很小
每个敌人都用一个 Area3D 实现视野宽相位处理负担加重距离、锥形范围、单条射线 [新增]
信任对传送后的物体进行射线检测的结果敌人“看穿”墙壁检查陈旧命中结果的距离
命中区域的层和遮罩都设为 1命中自身,造成三倍伤害只设置遮罩或层;使用 HitLog
在 area_entered 中设置 monitoring = false“在进出信号期间禁止调用函数”使用 set_deferred
子弹刚体使用默认层1000 个刚体发生碰撞:每帧 110 到 170 ms使用独立层,遮罩设为 world 和目标
高速刚体未启用 CCD子弹以 30 m/s 的速度穿过墙壁使用 continuous_cd 或射线扫掠数据
加载下载的 .tres其中的脚本会运行使用 load_resource_checked 或配合 from_native 使用 JSON
重新保存后仍使用默认 load()旧值再次出现CACHE_MODE_IGNORE
对 Array[String] 执行 save.items = [...]运行时错误,或通过 set() 静默无效使用 items.assign([...])
每个箱子都预加载库存 .tres所有箱子都显示同一个箱子的战利品为每个持有者调用 duplicate(true)
Selector 中第一个子项总是成功攻击分支永远不会运行(Chap.C E_FIy2dTkNc 00:17:27)设置首项门控,使用 BTProbability 或 AlwaysFail
动作中使用逻辑键码使用 AZERTY 键盘时,WASD 操作失效使用物理键码
开启物理插值时进行传送刚体会在跳跃过程中滑动 [新增,未测量]移动后调用 reset_physics_interpolation()(该方法存在)
对自动加载单例调用 queue_free()在 4.7.2 中不会崩溃;之后每次访问都会因读取 0 而报“先前已释放”错误(文档称会崩溃)永远不要释放它;改为重置其状态

交接

  • **接收:*项目布局、自动加载策略和保存模型(scenario-godot-architecture);带有静态碰撞体的关卡(位于 nav_source)和控制器(scenario-godot-3d-world);TileMapLayer 导航(scenario-godot-2d);来自 scenario- 技能的美术资源,通过上述两个技能交付。
  • **交付:**将 state_changed 交给 scenario-godot-animation;将播放事件和优先级交给 scenario-godot-audio(混音、总线、衰减和监听器由该技能负责);将物品栏信号、对话气泡和按键重映射菜单交给 scenario-godot-ui;将命中位置和法线交给 scenario-godot-vfx;将资源和纯 decide() 交给 scenario-godot-multiplayer;将基准测试 JSON 交给 scenario-godot-performance-export。

Godot 4.7 注意事项

  • 导航类在 4.7.2 中属于实验性功能。区域和地图迭代默认异步执行,因此同步需要耗费数帧。region_bake_navigation_mesh 已弃用:请改用 parse_source_geometry_data 加 bake_from_source_geometry_data(或其异步版本)。region_get_iteration_id 已存在。query_path(params, result, callback) 会在返回前执行回调(P15):它不会将工作移出当前帧。
  • MultiMesh 会将所有实例作为一个包围盒进行剔除:设置 custom_aabb(已存在),并按区域拆分大型人群。
  • NavigationMesh 的默认 geometry_parsed_geometry_type 为 Both(2)。默认单元格大小和高度为 0.25。
  • 从 4.6 开始,新项目默认使用 Jolt 作为 3D 物理引擎,但由 Agent 编写的 project.godot 会使用 GodotPhysics3D,除非明确设置 Jolt(负责人的差异)。
  • duplicate(true) 只会复制文件内部的子资源(4.5 及更高版本)。 duplicate_deep(DEEP_DUPLICATE_ALL) 也会复制外部资源。
  • JSON.from_native 和 to_native 已存在;普通 JSON 数字会以浮点数形式返回。
  • InputEventKey.as_text() 会打印 "W - Physical"。新建的 InputEventKey 的设备 ID 为 16 (DEVICE_ID_KEYBOARD)。
  • 插件:Dialogue Manager 的版本为 4.1.0,其中标题是提示语;DM3 视频内容落后一个版本。 LimboAI 1.8.1 附带一个标为 "4.6" 的 GDExtension 构建版本,可在 4.7.2 上运行。

参考资料

  • references/procedures.md(P0 至 P15,含代码和实时结果), expert-notes.md(专家判断及时间戳),critique.md (评估标准),gui-paths.md(编辑器菜单), sources.md(视频、文档、插件哈希值)。
  • scripts/gd_gameplay.py:安装、run_job、crowd_bench、 scaling_verdict、budget_share、对话 lint、存档扫描。
  • scripts/agentkit/gameplay/:nav_tools、arena、crowd_bench、 enemy_body、状态机及状态、brain、perception、enemy_manager、hitbox、hurtbox、hit_log、 combat_layers、bullet_pool、save_io、inventory、quest_rules、dungeon_gen、voice_pool。

评论

支持 Markdown