5.1. Sync 包概览

Sync 是**单一 GDExtension** 的通用节奏游戏引擎包:谱面数据模型、时间系统、 编辑器组件与运行时全部打包为 addons/sync 一个插件(入口 sync_library_init,一个 DLL,注册全部 19 个类)。

0.5.0 起,原来的三个插件(数据层 / 编辑器组件 / 运行时)已合并为 这一个包——不再有"需要哪个包"的组合安装问题,也不再有包间依赖、 加载顺序约束与跨扩展桥接。

5.1.1. 类一览(19 个)

继承

类别

用途

SyncDocumentChart

Resource

共享数据

谱面根文档(编辑 / 保存 / 加载 / 编译)

SyncTrack

Resource

共享数据

轨道节点(音符 + 子轨道 + 动画轴)

SyncNote

Resource

共享数据

单个音符(kind:0=TAP / 1=HOLD)

SyncBeat

Resource

共享数据

音乐时间值(beat + numerator/denominator)

SyncBpmAxis

Resource

共享数据

BPM 关键帧曲线,拍 ↔ 毫秒互转

SyncTimeSignatureMap

Resource

共享数据

拍号变化关键帧集合

SyncFloatAxis

Resource

共享数据

浮点值关键帧动画轴

SyncVector2Axis

Resource

共享数据

Vector2 关键帧动画轴

SyncVector3Axis

Resource

共享数据

Vector3 关键帧动画轴

SyncVector4Axis

Resource

共享数据

Vector4 关键帧动画轴

SyncSpeedAxis

Resource

共享数据

速度关键帧轴,归一化位置采样

SyncTrans

RefCounted

共享数据

过渡类型常量(STEP / LINEAR / SINE / ...)

SyncEase

RefCounted

共享数据

缓动方向常量(IN / OUT / IN_OUT)

SyncProgressManager

Node

编辑器组件

谱面伴生播放引擎(制谱 / 预览用)

SyncTimeline

RefCounted

编辑器组件

归一化坐标映射(底部 0 / 顶部 1)

SyncBeatGrid

RefCounted

编辑器组件

节拍线数据输出(不做渲染)

SyncChart

RefCounted

运行时

编译后的只读谱面

SyncChartPlayer

Node

运行时

墙钟驱动的播放器

SyncNodePool

Node

通用组件

绑定 PackedScene 的节点对象池

5.1.2. 核心层

数据层核心以 C++17 实现(sync::core 命名空间,位于 include/sync/ + src/core/),作为 GDExtension 的底层实现; 同时产出静态库(build/),供测试与纯 C++ 调用方直接使用。 内部模块:

模块

内容

Math

Vec2/Vec3/Vec4、缓动函数、过渡/缓动枚举

Time

Beat、BpmAxis、TimeSignatureMap

Chart

DocumentChart / PlayChart、Note(TAP / HOLD)、Track、动画轴

Player

ChartPlayerCore、播放事件

Timeline

归一化坐标映射、节拍线数据生成

5.1.3. GDExtension 层

Godot 包装层(godot:: 命名空间,位于 include/sync_godot/ + src/godot/)把核心类包装为 Godot 可反射的类,并在 register_types.cpp 中**一次性注册全部 19 个类**。产物为 addons/sync/sync.gdextension + bin/)。

0.5.0 合并后**没有跨扩展问题**:三个旧包之间曾经的跨扩展桥接 / 导出宏 / 导入库链接随合并一并移除;包装类的公开接口直接使用 Ref<T> 等具体 C++ 类型,GDScript 侧所有 Sync* 类来自同一个 DLL,无加载顺序约束。

5.1.4. 不含判定 / 不含渲染

重要

Sync 不内置判定引擎。判定是游戏的代码。

引擎只保留两种时间语义:kind=0TAP (单点)与 kind=1HOLD (区间)。游戏专属的音符种类(CATCH / VOID / 长键 / 滑键等)没有专用 kind,写在 note.metadata (如 metadata["note_type"] = "catch"),由你的 GDScript 判定按字符串 分发——引擎对它们"完全透明",可见性、位置采样、序列化行为与 TAP 完全一致。

同时引擎**不做任何渲染**:没有轨道绘制、没有音符精灵、没有 UI 组件。编辑器组件(SyncTimeline / SyncBeatGrid)只输出归一化坐标 与节拍线**纯数据**,渲染由你的 GDScript / shader 完成。

引擎保证判定所需的全部数据精确可用:

需要

API

当前谱面毫秒

SyncChartPlayer.get_chart_progress_ms()

谱面静态信息(判初枚举)

SyncChart.get_track_ids() + get_note_ids_for_track()

每个音符的精确数据

SyncChart.get_note_info()kind / hit_time_ms / end_time_ms / is_hold / metadata

当前可见音符(每帧渲染)

SyncChartPlayer.get_visible_note_ids_for_track() / get_visible_notes_info()

BPM 网格(HOLD tick 等)

SyncBpmAxis.beat_to_ms() / ms_to_beat()

轨道动画状态

SyncChartPlayer.sample_track_*_axis() / get_track_normalized_position_at()

5.1.5. 组件速览

编辑器组件 (制谱 / 预览场景)

  • SyncProgressManager — 谱面伴生进度引擎,内置时钟驱动播放、 seek、逐拍导航与变速(playback_rate

  • SyncTimeline — 谱面毫秒 ↔ 归一化位置双向换算 + 输入反推节拍

  • SyncBeatGrid — 可见窗口内全部节拍线的纯数据输出

统一约定:时间 = 毫秒、坐标 = 归一化 0~1(底部 0 / 顶部 1)、 progress_ms=-1 哨兵 = 取绑定的 progress_manager 当前进度。

运行时 (游戏场景)

  • SyncChartPlayer — 墙钟驱动播放器;set_document_chart 内部把 SyncDocumentChart 编译为 SyncChart (PlayChart)。0.6.0 起支持 外部时间源注入(step_ms / set_chart_time_ms)与事件窗口参数化 (set_event_window_ms / set_max_events

  • SyncChart — 编译后的只读谱面,可从任意线程安全访问。0.6.0 起可按 hit 时间窗口查询音符(get_note_ids_in_time_window),免疫速度轴跳变

通用组件

  • SyncNodePool — 绑定 PackedScene 的节点对象池 (acquire / release / prewarm),编辑与游玩侧共用

5.1.6. 构建与测试

# 1) 核心静态库
cd OpenSource/Sync
scons                        # debug;scons mode=release 为 release
python run_tests.py          # 逻辑测试(g++ 直编),必须全绿

# 2) GDExtension(全 19 类 + DocData)
scons -f SConstruct.extension target=template_debug platform=windows
scons -f SConstruct.extension target=template_release platform=windows

测试套件(全部必须绿):test_math (Vec/Vec/缓动)、test_time (Beat/BpmAxis 拍-毫秒互转)、test_chart (谱面构建、轴采样)、 test_player (可见性)、test_timeline (坐标映射与节拍线生成)。

demo 项目位于 Sync/project/,headless 验证:

godot --headless --quit-after 600 --path OpenSource/Sync/project

详细 API 参见 Sync API 参考