记录操作过程,也保留可查看的回放
驾驶训练既需要知道“这次做得怎样”,也需要查看“当时怎样操作”。成绩表适合查询完成时间和行为次数,连续数据能显示方向盘、刹车和速度的变化,场景回放则用于重新观看驾驶过程。我参与的实现将这些记录分为过程 JSON、成绩 JSON 和 UE Network Replay。
接入时,统计界面可以读取成绩,分析工具可以读取曲线;需要重看场景时,再通过引擎回放管理录制文件。即使字段相似,或来自同一次训练,这几种数据也不能直接互相替代。
驾驶数据与成绩统计
采样时间与批次
过程记录由 WorldSubsystem 在初始化时自动启动,并在 Tick 中采集车辆状态。时间轴使用从墙钟起点开始计算的经过秒数,车辆位置从 UE 的厘米换成米,再进入记录结构。
缓冲达到 3000 条样本时触发一批数据处理。这里的 3000 是样本批次阈值,不是固定采样频率,也不是保证每隔固定秒数生成一份数据。Tick 频率变化时,单位时间内得到的样本数量也会变化;读取曲线时应使用保存的时间坐标。
连续曲线与状态事件
连续变化的值进入各自通道,档位、转向灯则按值改变记录事件。这样既保留操作随时间变化的形状,也避免把持续不变的离散状态当作每帧新事件。
| 数据类别 | 记录内容 | 组织方式 |
|---|---|---|
| 操作输入 | 方向盘、刹车、油门 | 按通道形成连续曲线 |
| 车辆与观察状态 | 速度、头部朝向 | 带时间坐标的通道数据 |
| 空间信息 | 世界位置与方向的 X、Y、Z 分量 | 分通道保存,位置统一为米 |
| 离散状态 | 档位、转向灯 | 记录发生变化的时间与值 |
生成的 JSON 包含会话字段、曲线 ControlPoints 和离散 Events。分析端可以按通道读取操作变化,也可以在事件时间上对照档位或灯光状态,避免把所有字段都解释成同一种采样值。
曲线拟合与误差口径
原始点按通道拟合、简化,再保存控制点。误差阈值作用于 (time, value) 平面中的拟合距离,时间和字段数值一起参与判断。方向盘、速度与空间位置的单位不同,同一数值阈值不能直接解释成相同的物理误差。
减少关键点的目的是用较少数据描述变化曲线,但需要保留的突变、允许的误差和使用方式仍由业务决定。例如查看刹车开始的时刻,与观察一段速度趋势,对曲线细节的要求就不同。实现采用了按通道处理的结构,没有在这里承诺压缩比例或统一物理精度。
后台保存与完成通知
序列化和文件写入放到后台执行,同一路径使用锁协调写入,并可把完成回调送回游戏线程。这让文件操作与逐帧采样分开,但“已经发起保存”与“文件已经写完”仍是两个状态。
当前采集调用方没有绑定完成回调,也没有在退出时等待保存结束。因此,异步保存机制不能保证程序退出时最后一批数据必然落盘。需要在结束时可靠留档的项目,应把完成通知和退出流程纳入接入范围。
成绩统计单独组织
成绩 JSON 保存成绩标签、转向与起步次数、完成时间、反应时间和日期,并提供记录筛选。它面向一次训练的结果查询;过程曲线则保留操作和状态变化。两者可以在业务界面中配合查看,但应保留各自的结构和含义。
复用 UE Network Replay
场景回放使用 UE Network Replay,管理接口封装开始录制、播放、枚举、重命名和删除。界面可以选择已有录制并发起播放,不需要把过程曲线重新解释为引擎的全部场景状态。
这里的过程采集、成绩统计和引擎回放是三种配套机制。过程 JSON 没有承担重建完整场景的自研回放引擎职责;需要重现的 Actor、复制状态及具体回放表现,要按项目的 UE 回放配置检查。数据查询、文件管理与场景回看因而可以分别确定验收要求。