关于 godot-game-loop-time-trial
godot-game-loop-time-trial 是用于 Godot 竞速计时赛的技能,涵盖按序验证检查点、精确计时和视觉幽灵回放。它指导开发者构建管理器、检查点、记录、回放及排行榜组件。
主要功能
- 01按序验证检查点
- 02微秒或物理帧计时
- 03记录变换与 Quaternion 旋转
- 04插值播放幽灵轨迹
- 05格式化排行榜时间
适用场景
- 01构建基于检查点的竞速计时器
- 02录制并回放幽灵路线
- 03保存最佳时间和幽灵数据
- 04为排行榜格式化圈速记录
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thedivergentai/ game-dev-agentic-skills --skill godot-game-loop-time-trial安装后在 Claude Code 中输入/godot-game-loop-time-trial确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/migration-notes.mdtime-trial-expert-patterns.mdscripts/ghost_recorder.gdghost_replayer.gdtime_trial_leaderboard_bridge.gdtime_trial_manager.gdtime_trial_patterns.gdtime_trial_playback_buffer.gd详细介绍
架构设计: “验证链”模式
Master 实现将计时赛视为一个经过状态验证的序列。记录时间很容易;要确保玩家没有通过走捷径作弊,则需要一个严格有序的 CheckpointManager。
核心职责
- TimeTrialManager:中央计时器。验证检查点顺序并处理“最佳圈速”逻辑。
- GhostRecorder:采集高频变换数据。使用增量时间戳,实现与帧率无关的回放。
- Checkpoint:空间触发器,用于通知 Manager。
专家级代码模式
1. 稳健的检查点验证
要求按数字顺序通过检查点,防止“走捷径作弊”。
将 Area 的 body_entered(物理)连接到 → TimeTrialManager.pass_checkpoint(index)。计时器由 Manager 管理(单位为 usec)——请参阅脚本。
2. 节省空间的 Ghost 记录
以固定频率采样(例如 10 Hz)。对位置进行 Lerp;对旋转使用 slerp Quaternion(ghost_recorder.gd / ghost_replayer.gd)。绝不要对 Ghost 朝向进行欧拉角 Lerp。
Master 决策矩阵:数据存储
| 格式 | 最适合 | 实现方式 |
|---|---|---|
| Dictionary Array | 原型设计 | 简单的 [{t: 0.1, p: pos}, ...] |
| Typed Array | 性能 | 使用 PackedVector3Array 存储位置。 |
| JSON/Binary | 保存 | 使用 FileAccess.get_var() 保存 Ghost 文件。 |
绝对不要做
- 绝对不要使用 OS.get_ticks_msec() 进行超高精度的竞速计时 — 毫秒级精度对于高端竞速游戏来说太粗糙。请使用
Time.get_ticks_usec(),以获得微秒级精度。 - 绝对不要只依赖 _process() 触发终点线检测 — 延迟期间可能会跳过画面帧。务必在
_physics_process()中检测物理重叠,确保在固定物理步长内完成检测。 - 绝对不要在实例化后立即检测 Area3D 重叠 — 物理服务器至少需要一个物理帧来完成同步。在检查玩家之前,先执行
await get_tree().physics_frame。 - 绝对不要对检查点上的 CollisionShape3D 使用非等比缩放 — 这会破坏底层的 SAT 碰撞计算。应始终缩放内部形状资源(例如
BoxShape3D.size)。 - 绝对不要在多人竞速中使用 TCP(可靠传输)同步位置 — 拥塞算法会造成巨大的延迟峰值。对于高频位置更新,请使用
ENetMultiplayerPeer和TRANSFER_MODE_UNRELIABLE。 - 绝对不要信任客户端对终点线或圈数的判定 — 务必在权威服务器上使用
multiplayer.is_server()验证触发事件,以防作弊。 - 绝对不要使用标准浮点数相等比较(==)来比较纪录圈速 — 使用
is_equal_approx(),以应对累积时间变量中的精度损失。 - 绝对不要在不清空缓冲区的情况下硬编码输入检测 — 为了实现帧级精准的加速/停止响应,请调用
Input.flush_buffered_events(),确保引擎已处理最新的原始输入。 - 绝对不要在快速路径跟随循环中分配新的 Vector3 数组 — 这会触发垃圾回收。请使用
PackedVector3Array来维持连续内存块。 - 绝对不要在紧密循环中使用动态字符串路径($"../Checkpoint") — 查找速度很慢。请使用
@onready在初始化期间缓存节点引用。 - 绝对不要为幽灵记录整个玩家对象 — 只记录核心变换(位置/旋转)。记录整个对象会消耗大量内存,而且对于视觉幽灵来说没有必要。
- 绝对不要给幽灵添加碰撞 — 幽灵应该只是视觉指示器(例如半透明),以免干扰玩家的行驶路线。
- 绝对不要忽略检查点顺序 — 不要只检查玩家是否到达终点线。请确认玩家按正确顺序通过了所有中间检查点。
- 绝对不要在未优化监测的情况下使用 Area3D — 检查点只应检测
Player物理层,以尽量减少物理重叠计算次数。 - 绝对不要对幽灵旋转使用标准 lerp — 使用
slerp()或Quaternion.slerp(),以避免万向节锁并确保旋转插值平滑。
可用脚本
必须遵循:按照黄金路径顺序操作。在为对应阶段编写代码前,先阅读其中列出的脚本。
黄金路径(必须遵循)
time_trial_manager.gd— 使用微秒(Time.get_ticks_usec)或物理帧计时;只能通过物理重叠/Area 信号调用pass_checkpoint- 检查点 Area — 使用有序索引指向管理器(基于物理帧,而非
_process) ghost_recorder.gd— 采样{t, p, q},其中旋转使用 Quaternionghost_replayer.gd— 位置使用lerp,Quaternion 使用slerp(绝不使用 Euler lerp)time_trial_leaderboard_bridge.gd— 将整数微秒/毫秒转换为 UI 字符串
脚本索引
time_trial_patterns.gd
10 种专家模式:微秒计时、服务器权威验证、橡皮筋 AI,以及帧级精准的输入缓冲区清空。
time_trial_manager.gd
中央时钟。累积 Time.get_ticks_usec()(或物理帧计数)。终点检查必须通过物理重叠触发。
ghost_recorder.gd
捕获包含 Quaternion "q" 字段的变换样本,以便安全地使用 slerp 播放。
ghost_replayer.gd
与录制器配套的必备脚本。通过位置 lerp + Quaternion.slerp 重放样本。
time_trial_playback_buffer.gd
用于网络流传输期间流畅回放幽灵数据的抖动缓冲区。
time_trial_leaderboard_bridge.gd
用于将原始时间数据转换为易读字符串的格式化工具。
专家级计时赛模式
1. 幽灵数据的增量压缩
仅当位置/旋转变化超过阈值时才存储关键帧。使用 FileAccess.open_compressed() + ZSTD 持久化;优先使用二进制浮点数,而非 JSON。
2. 排行榜桥接工具
以 int 微秒/毫秒存储记录。使用 %02d:%02d.%03d 格式化,确保 UI 稳定显示(例如 01:24.450)。
专家知识(按需获取)
**大模型无知规则:**如果通用 Agent 在阅读前不会了解某项内容,就加载参考资料 — 永远不要删除专家增量内容。
- time-trial-expert-patterns.md — 恢复基础教学内容(架构、原因、实现深度)
参考资料
渐进式披露:仅在研究特定 API 时打开官方文档链接;在切换到相邻领域时加载相关技能 — 不要预加载整个知识网络。
官方文档
- 时间 — 当
OS.get_ticks_msec()对比赛记录而言精度不足时,使用get_ticks_usec()获取微秒级单圈计时。 - 空闲与物理处理 — 说明终点线和检查点的重叠检测为何必须在
_physics_process中运行,而不能依赖负载较高时可能跳过的视觉_process帧。 - Area3D — 通过监控、碰撞层和
body_entered,按顺序设置检查点门,无需扫描每个物理物体。 - 碰撞形状(3D) — 调整形状资源(
BoxShape3D.size)的大小,而不是对CollisionShape3D使用非均匀缩放,以确保门上的 SAT 有效。 - 使用变换 — 说明如何为幽灵样本捕获全局位置/基底,以及为何仅存储欧拉角时需要谨慎进行回放转换。
- Quaternion — 在关键帧之间使用
slerp(),避免幽灵朝向在朴素欧拉角线性插值时出现万向节锁。 - Transform3D — 使用
interpolate_with()在有序帧之间回放抖动缓冲的网络幽灵数据。 - 保存游戏 — 使用
FileAccess/store_var模式持久化幽灵跑圈数据和最佳时间字典,避免浮点数显示往返转换。 - 高级多人游戏 — 使用服务器权威 RPC 验证,防止客户端伪造单圈/终点线穿越。
- MultiplayerPeer — 对高频赛车变换使用
TRANSFER_MODE_UNRELIABLE,避免类似 TCP 的可靠传输导致延迟激增。 - 输入 — 当帧级精度的加速/停止操作必须在物理步进前读取最新原始输入时,使用
flush_buffered_events()。 - Engine — 使用
physics_ticks_per_second/get_physics_frames()将整数帧计时桥接到 MM:SS.mmm UI。
相关技能
前置条件
- godot-project-foundations — 在将
TimeTrialManager和检查点区域接入赛道场景前,先了解场景树、自动加载项和资源布局。 - godot-physics-3d — 了解 Area3D/CollisionShape3D 层、RigidBody/CharacterBody 载具,以及确保检查点顺序可靠的物理帧重叠规则。
- godot-signal-architecture — 在闸门、管理器、HUD 和幽灵系统之间传递类型化的单圈/分段/完赛信号,避免脆弱的节点路径耦合。
- godot-gdscript-mastery — 掌握计时和权限模式中用到的类型化数组、Packed* 缓冲区、
await physics_frame和 RPC 注解。
补充
- godot-input-handling — 时间挑战 NEVER 规则要求在物理帧前清空的动作映射和缓冲加速/转向输入。
- godot-save-load-systems — 超越内存样本数组,了解压缩二进制幽灵文件和最佳成绩持久化。
- godot-multiplayer-networking — 用于实时比赛和流式传输幽灵帧的 ENet 对等节点、权限和不可靠变换同步。
- godot-adapt-single-to-multiplayer — 将单人时间挑战扩展为在线竞速时所需的延迟补偿、快照和兴趣管理模式。
- godot-navigation-pathfinding — 使用 NavigationServer3D Agent 的最高速度设置橡皮筋 AI,使其与玩家保持节奏,同时不通过碰撞作弊。
- godot-monte-carlo-balancer — 在发布挑战参数前,模拟橡皮筋系数、检查点难度和目标通关时间。
- godot-camera-systems — 追逐/回放摄像机必须在播放期间跟踪实时赛车和无碰撞的幽灵视觉效果。
下游 / 使用方
- godot-genre-racing — 完整的竞速游戏类型技术栈,将检查点计时、幽灵和排行榜格式作为核心循环基础机制。
- godot-game-loop-collection — 元游戏库存/收集循环,可依据此技能验证过的最佳成绩来设置解锁条件。
主模块
- godot-master — 用于跨技能发现的库路由器和镜像模块入口。