从空间构图到时序响应:用 AI 验证相机、后坐力、弹道与 UI 的一致性
阅读上篇:AI 原生开发实战·TPS 相机改造(上):机位与构图的量化对齐
上篇解决的是 TPS 相机的空间构图:机位位置、角色占屏比例,以及站、蹲、趴三种姿态下的腰射与肩射构图。静态画面对齐后,动态体验仍然存在明显差异:参考图相近,并不意味着运动过程已经一致。
原因是截图只冻结了一个结果,而手感存在于结果之间。
体验调优从来不缺参数。难的是玩家只会告诉你“不跟手”,而程序需要知道这句话究竟落在哪个参数、哪一层系统上。AI 在这里也不负责替人挑一个更顺眼的数字。它更适合把观察、假设、实验、采集和验证串起来,让下一轮不再从猜开始。
所以这篇表面上还在讲 TPS 相机,实际追的是另一个问题:
AI 怎样把原本依赖资深开发者直觉的“感觉问题”,转化成可以测量、实验和复用的工程流程?


AI 在体验分析中的职责
这两周的工作中,AI 主要承担三类任务。
将主观描述转成可观测现象。
AI 读取录像、寻找变化区间、提取时间和空间特征,把“进镜有点拖”“后半梭子不动”“弹孔好像偏了”改写成可以验证的描述。体验是否成立仍由人工验收,AI 负责先把问题定义清楚。
把现象拆到可能的控制层。
同一句“枪不跟手”,背后可能是相机过渡、位置 lag、后坐力恢复、枪口动画、弹道会聚,也可能是准星反馈没有同步。AI 沿调用链列出假设,并为每个分支设计最小实验。这个阶段最重要的产物通常不是答案,而是按证据成本排序的排查顺序。
组织交叉验证。
参考录像定义体验目标,探针和日志记录运行时行为,网页工具完成曲线对照,人工体验验收决定方案是否保留。AI 负责整理差异、识别异常并准备下一轮测试,不替代验收判断。
实际流程分为八步:
- 记录玩家原话,不急着翻译成参数;
- 把体验拆成可观察现象;
- 建立可能控制层的假设树;
- 设计一次只改变一个变量的最小实验;
- 同时采集画面证据和运行时证据;
- 找到控制最终输出的层级;
- 修改后做正向效果与反向边界验证;
- 把探针、日志、图表和规则沉淀为下一次的起点。
后面的三个核心案例——StageDelay、失效的 lag 和稳定左下偏移——分别展示了这条闭环在参考系、状态保存和控制层定位中的作用。
传统流程经常退化为“玩家反馈 → 参数猜测 → 试玩 → 再次猜测”。本次 AI 主要参与中间环节:拆分现象、建立假设并设计最小实验。它将可能原因转换为可验证的顺序,体验是否成立仍由人工判断。
从腰射进入肩射需要多久?松开瞄准后如何退出?贴镜是连续推近,还是在特定帧切换?角色横移时镜头以何种速度跟随?连续发射一个弹匣时,相机、枪口、弹着点和准星是否保持同步?这些问题都属于时序响应,而非静态空间坐标。
为便于分析,我们将动态反馈拆成五条相互关联的时序链路:
- 相机钟:机位和视场什么时候到位。
- 后坐力钟:视角什么时候上抬、摆动、恢复。
- 弹道钟:子弹实际从哪里出发、飞向哪里。
- 动画钟:枪和角色的姿态怎样遮挡或带动视线。
- UI 钟:准星什么时候出现、展开、收拢。
任一链路出现提前、延迟或恢复速度不一致,最终都会表现为瞄准与射击反馈不同步。
下篇要算的就是这笔账:相机手感来自多个反馈系统在同一条时间轴上的配合。



*HD2 参考证据 A:同一批录像里的第三人称腰射、第三人称肩射和第一人称贴镜。这里看的是构图层级、角色占屏与观察模式的切换,不把单帧截图当成完整的时间曲线。*
一、零点五秒内的状态变化
第一个案例处理的是时序偏差。初始判断集中在过渡时长,逐帧分析随后将问题定位到计时参考系。
最初的过渡配置看起来很简单:腰射、肩射、贴镜三个端点,两段插值,再配几个时长。可一旦开始逐帧对照,“时长”就拆成了三个问题:
- 从哪一帧开始计时;
- 中间经过哪些状态;
- 哪一帧达到目标状态。
从参考录像逐帧测量得到的观测值是:举枪进入肩射约 0.20 秒,松开后退回腰射约 0.25 秒,肩射与贴镜之间则是近似瞬时切换。它不是一条对称曲线。进入状态更果断,退出稍微留一点重量;贴镜也不是把肩射推近动画再播一遍,而是一个明确的观察模式切换。
我们一度给“阶段延迟”填入一个较小值,希望镜头到达肩射端点后短暂停留再进入贴镜。运行结果却显示,延迟和推进从同一时刻开始计时。原本计划调整端点停留,实际改变的是整段混合的起点。
数字本身没算错,参考系读错了。
这形成了时序响应分析的第一条规则:
调整任何时长之前,必须确认计时器的起始帧。字段名称表达设计意图,实现代码才定义实际参考系。
随后将三段行为改写为明确的时间线,不再依据单一“过渡时间”字段推测系统行为:
- 腰射 → 肩射:连续推进,约 0.20 秒;
- 肩射 → 腰射:连续退出,约 0.25 秒;
- 肩射 ↔ 贴镜:双向硬切;
- 腰射直接贴镜:先完成快速举枪,再在端点切入贴镜。
这样也能统一处理过渡中的反向输入:系统从当前进度继续计算,不再跳回端点重新播放。短暂停顿、位置突变和快速输入后的状态错误,由此归并为同一类状态连续性问题。
这些时长并非仅通过录像计时获得。肩射推进时,角色、武器模型和场景同时运动,单一轮廓难以确定起始帧,因此需要组合三种判读方法。
三种手段各有分工:帧差脉冲寻找整幅画面从哪一帧开始变化;场景中随瞄准状态改变亮度的发光物充当状态探针;把候选帧裁成窄带横向排列的胶片带,则显示推进方向和结束帧。
三类工具分别回答不同问题:帧差确定运动起点,状态探针确认当前状态,胶片带显示运动方向和结束帧。三份证据一致后,0.20 秒、0.25 秒和 1~2 帧硬切才成为可复查的观测结论,而非主观播放感受。
将该问题整理为可复用的案例格式如下:
- 问题:参考录像端点零停留,工程却有拖延感;
- AI 的错误假设:字段名代表“到达端点后的停留时间”;
- 最小验证:把值压到 0.03 秒,观察推进是否仍能走完;
- 人工判定:体验明显恶化,立即否决;
- 最终定位:字段从分段起点计时;当前测试环境的工程参数选择约 0.22 秒,以覆盖完整推进并留出一帧余量;
- 沉淀规则:修改时长前,先在实现里确认计时参考系。

*证据帧 A:腰射推进到贴镜的逐帧变化。黄色数字为录像时间;绿色发光物是用于判断状态切换的画面探针。*
二、ADS 的问题不在切得快,而在底层还在动
贴镜切换最初通过了视觉验收:画面几乎在一帧内完成,与参考录像一致。但扩展到不同姿态后出现了不对称现象:站姿退出稳定,蹲姿偶尔出现拖尾;进入贴镜已完成硬切,退出时最终画面仍有缓慢位移。
分层检查确认 ADS 曲线本身没有问题:上层已经切完,底层仍在插值。
相机最终位置由多层叠加得到。贴镜层切到终点,只说明这一层完成;如果基础机位层还在从肩射配置追向贴镜配置,最终画面照样会缓慢漂移。不同姿态的分支顺序又不完全相同,所以同一段代码表现成了站、蹲不对称。
没有继续增加更快的 ADS 曲线,而是逐层核对最终相机变换:
- 贴镜层在进入和退出时直接落端点;
- ADS 期间冻结不该继续追赶的基础偏移;
- 退出时先恢复正确的目标层,再交回普通肩射混合;
- 三种姿态走同一套状态顺序,只读取不同端点数据。
修复后,“瞬时切换”作用于玩家看到的合成画面,而不再只表示某个变量已经归零。
定位这个问题时,我们用了一个很简单的分层实验。先冻结贴镜层,只看基础机位是否还在动;再冻结基础层,只让贴镜层切换;最后恢复合成。单独看两层时,它们都“没有 bug”:基础层按照自己的目标正常收敛,贴镜层按照需求瞬时到位。只有合成后,两个正确行为才构成一个错误结果。
这类问题容易被误判为过渡时长过长。若底层仍保留 0.08 秒拖尾,将上层从 0.02 秒改为 0 并不能消除最终位移。更有效的方法是逐项隔离合成结果:基础姿态、瞄准叠加、碰撞修正、lag 和视场偏移都可能保留时间残差。只有完成分层验证,“慢”才能转化为可定位的问题。
这次故障给了我们一条比“硬切要设成零秒”更有用的经验:
分层系统的验收对象必须是最终消费点。上层变量到位,不等于最终画面到位。


*项目画面 A:同一位置、同一朝向下的站姿第三人称腰射。角色尺度、屏幕中心和基础准星共同构成后续对照基线。*

*项目画面 B:按住瞄准进入肩射后,镜头推近并改变角色构图,但仍保留第三人称动态准星。*

*项目画面 C:从同一位置进入 ADS,观察模式切到第一人称瞄具;三张图共同说明腰射、肩射和贴镜并不是一个缩放量的三个数值。*
三、移动跟随:失效插值的定位与恢复
第二个案例首先验证参数对应的运行链路是否有效,而非立即评价参数数值。该顺序避免继续优化一段实际上没有跨帧状态的插值。
相机空间与切换节奏确定后,角色横移时镜头仍与人物完全同步,缺少参考录像中的缓动跟随。工程中已经存在位置跟随参数并调用插值函数,但运行结果没有显示相应效果。
原因是每帧先将插值起点覆写为目标值,随后又从目标插向目标。
代码结构、函数调用和配置参数均已存在,缺失的是上一帧相机位置。没有跨帧状态,插值函数每帧都从当前目标重新开始,因而无法形成可见滞后。该问题难以通过静态代码结构发现,因为所有功能入口表面上都已齐全。
初次检查确认插值函数、速度参数和配置入口均已存在,因此判断一度集中在“数值过快”。记录连续两帧的起点、目标和结果后,日志直接显示起点恒等于目标。功能入口存在,但跨帧状态并未建立。
不需要换算法,只需要把跨帧状态补回来:
- 第一次进入时记录当前位置;
- 每帧从上一帧结果追向新目标;
- 将结果留给下一帧;
- 状态切换或瞬移时显式重置,避免拖尾穿越。
位置探针在一次稳定复测中记录到约 28.5 厘米的稳态相对偏移,停止后约 0.22 秒明显收敛——这是证明链路已经工作的项目观测值。随后进行速度分档 A/B,当前测试环境最终选择约 k=8 作为工程参数,对应同一曲线族中约 43 厘米的稳态滞后和约 0.28 秒的收敛。它不是跨项目通用答案,而是参考节奏在本地相机尺度中的具体实现值。
期间还出现过两次无效测试。第一次录像没有任何有效曲线,原因是测试未进入实际游戏状态;第二次画面表现为相机停止响应,原因是窗口焦点改变了视角输入路径。两次均无需修改代码,因为探针已证明核心链路有效,问题来自测试条件。
探针随后增加采样帧数、有效位移帧数和状态标签,并对空数据直接报警;测试协议也明确为“仅输入位移,不混入视角旋转”,先隔离位置跟随,再回到复合输入验证体验。
这件事改变了我们的排查顺序:
先证明测试条件成立,再证明数据链路工作,最后才调参数。没有健康度检查的录像,只是一段昂贵的猜测。
同样用案例格式复盘:
- 问题:移动时镜头像焊在角色身上;
- 错误假设:跟随速度过高;
- 最小验证:逐帧记录插值起点、目标和输出;
- 最终定位:上一帧结果没有保存,起点每帧被目标覆写;
- 人工判定:链路恢复后进行速度分档 A/B,当前测试环境最终选择 k=8;
- 工具沉淀:位置探针、自检字段和纯位移测试协议。
四、开火反馈不是“加一点抖动”
这一节涉及不少武器参数,但目的不是展开枪械调参。开火反馈说明,玩家体验不会按照相机、动画、弹道和 UI 的代码目录分开出现。
按最初排期,相机工作应在这里结束,武器留到下一阶段。但进入开火验证后,这条边界失效了:玩家判断的仍然是整体镜头反馈。枪口、镜头、弹着点和准星在代码中分属不同模块,在体验中却共同构成一次射击。
因此,原本后置的武器反馈进入了本轮验证范围。
该过程形成了一项明确结论:体验问题不服从代码模块边界。 玩家感知的是一次完整开火,工程实现却由相机、动画、UI 和弹道共同完成。若 AI 仅检查最先被指出的模块,可能会在错误系统中高效地优化。
最初我们将开火反馈拆成四层结构:
- 每发输入的视角踢升;
- 连续受力与回正的弹簧;
- 枪械或相机内部的随机抖动;
- 动画骨骼和振子的视觉反馈。
实测后又补上第五层:弹道方向与散布。它不一定推动相机,却决定玩家是否相信镜头和准星。相机上抬、子弹不跟;准星展开、着弹却集中在左下角;动画看起来在后坐,射线仍打在固定一点——这些都会被统称为“后坐力不对”。
系统层数本身不是问题,缺少逐层观测才会导致误判。早期只调整数据表中的纵向和横向系数,却忽略旧版随机镜头抖动仍在叠加;关闭开火动画后左下偏移暂时消失,也一度使动画被误判为弹道控制层。后续验证表明,动画只是改变了另一条方向链路的可见性。
从那以后,每一层都必须回答三个问题:
- 它改变的是视角、枪模,还是实际射线?
- 它的输入单位是什么?
- 它只影响测试枪,还是所有武器?
这张账本一建立,“手感”才从一个总开关变成可验证的系统。
还需要区分两个经常出现在同一图表中的概念。蓝色相机线表示观察方向的变化,橙色弹着点表示子弹相对观察中心的位置。前者可以规律上升,后者可以在其周围随机分布;两者之间的距离才表示散布。早期预览将相机轨迹和弹道轨迹统称为“后坐力”,因此无法判断橙点偏离蓝线是合理散布,还是发射方向被其他系统改写。
因此图表也被迫升级了语义:空心点是相机瞄准中心,实心点是实际弹着点;连线分别表示视角历史和逐发顺序,不能再用一条折线含混带过。可视化不是结果的包装,它会反过来决定我们能不能正确提问。
五、两种真相:解包参数是输入,录像轨迹是输出
为还原参考作品中的制式步枪,我们同时使用了解包数据与录像观测。两类材料都会产生数值;若不先区分证据等级,容易形成虚假的精确性。因此,全文将数值分为三类:
- 观测值:直接从参考录像或运行日志测得,例如射速、屏幕位移和停火恢复时间;
- 工程值:项目中实际填写或选定的配置,例如过渡时长、跟随速度和姿态比例;
- 推导值:由画面比例、距离或视场换算得到的目标区间,必须保留假设和误差带。
第一类是数据侧输入。解包记录显示它拥有水平/纵向漂移、水平/纵向爬升、基础散布等字段:漂移约 7/10°/s,爬升约 5/20°/s,散布约 2 mrad。这些数字描述系统给武器施加了什么。
第二类是录像侧输出。逐帧测量得到:
- 录像测量射速约 632 RPM,与标称 640 RPM 接近;
- 录像测得贴镜单发永久上爬约 0.55 像素/发,几乎不回正;
- 录像测得第三人称肩射约 4.4 像素/发,约为画面高度的 0.81%/发;
- 第三人称停火后呈指数式回正,完整观感对应的时间常数约 0.30 秒。

*HD2 参考证据 B:Liberator 第三人称连射。单帧能显示瞄准姿态、目标面和弹着区域;真正的每发爬升与停火回正仍由整段录像逐帧测量。*

*HD2 参考证据 C:Liberator 贴镜连射。它和第三人称录像一起用于区分“TPS 踢起后回中”与“ADS 小步累积、几乎不回”的两类输出。*
这里的 632 RPM、0.55 像素和 4.4 像素都属于观测值,不是准备直接填进本地表格的目标参数;7/10、5/20 和 2 mrad 属于参考系统的输入数据;后文 19~24 厘米则属于带场景假设的推导区间。给数字标注身份,比继续增加小数位更能提高可信度。
最初尝试将输入字段逐项映射到工程数据表,并期望网页预览复现录像轨迹。结果表现为横向分布过大、轨迹先右后左且峰值高度不一致。原因是两个后坐力系统并不使用同一方程:名称相同的 Climb 或 Drift,不代表相同的积分、限幅、采样次数与恢复模型。
随机采样也曾造成误判。预览工具将多个随机数相加,却没有标明这是工具自身的建模选择,因而与运行时采样次数错位。页面随后改为与项目一致的采样顺序;固定种子用于复现比较,更换种子用于检查分布包络。随机系统需要对齐的是统计分布,而非单次样本。
于是证据分工被重新定义:
- 录像输出决定目标手感:爬多高、多久回、稳定段有多宽;
- 解包输入解释相对关系:纵向比横向强多少,哪一层负责漂移,散布量级在哪;
- 工程参数负责本地实现:不追求字段同名,而追求最终波形同形。
参数名称容易造成可直接映射的误解。跨引擎还原时,可迁移的是输出特征,原始输入数值通常不能直接复用。
输入真相回答“原系统怎样驱动”,输出真相回答“玩家实际看到了什么”。做体验对齐时,前者是地图,后者才是终点。

六、数据表多轮调整后弹道仍未产生散布
第三个案例最复杂。相机、动画、散布和第三人称会聚同时参与开火反馈,因此必须先拆分控制层,再讨论参数调整。
测试枪的目标已经很明确:只在这一把武器上还原参考步枪的肩射弹道,不改变项目现有武器的后坐力和相机。我们为它建立了专用配置和开关,理论上改表即可。
随后数轮测试反复出现以下现象:
- 改了横向系数,游戏里没有横向;
- 增加散布,子弹仍打在一个点;
- 网页模拟有变化,运行时后半梭子却完全不动;
- 某轮出现散布,下一轮又产生整体左下偏移。
最终确认数据表已经生效,但其输出之后还存在一层第三人称会聚计算。
在定位会聚层之前,首先核对了武器身份。控制台使用测试枪配置编号,运行时查表则使用另一套武器实体编号;后坐力表、散布表和外观动画还分别具有独立关联键。任一环节关联错误,都会表现为 CSV 已修改而运行结果不变。公开文章无须列出内部编号,但工程中必须建立“玩家获得的武器—运行时实体—后坐力行—散布行”的可追踪关系。
这条链还解释了另一个症状:前几发存在爬升,后半段变化却明显减弱。连续后坐力数组、循环数组和随机段会在不同发序接管;其中一段未正确绑定,前缀结束后就会进入重复值或零值。此后不再依赖单次弹匣的视觉结果判断数据表是否生效,而是在每个接管点记录当前发序、命中的表行和实际系数。
诊断案例:稳定左下偏移
现象:弹孔稳定从准星中心向左下延伸;修改后坐力表后,方向没有按预期变化。
假设树:表格符号错误、开火动画带偏枪口、旧镜头抖动污染观察、第三人称会聚改写方向。
AI 初始判断:优先怀疑纵横向参数和随机量,连续尝试调整表格。问题在于,表格输出当时尚未被证明是最终发射方向。
人工反证:随机量归零后偏移仍在;关闭开火动画曾让现象暂时消失,却不能证明动画直接改变子弹;隔离旧镜头抖动后相机轨迹更加清晰,弹孔偏移仍然存在。
最小验证:逐发同时记录表后方向、会聚修正和最终速度方向。这三个值第一次把“画面看起来偏了”拆成三个数据指纹不同的控制层。
最终控制层:表格散布之后,第三人称会聚再次根据相机射线目标和枪口位置求方向。枪口位于屏幕中心左下方时,这层几何修正制造了稳定偏移。
工具沉淀:诊断日志不再只打印一个 recoil 值,而是记录武器身份、视角状态、发序、命中表段、表格贡献、相机方向、散布后方向、会聚角差、最终速度和命中位置。完成一组弹匣测试后,日志即可判断偏移发生在数据表之前、之后,还是仅存在于画面表现中。
诊断的目标不是记录更多,而是让每一种可能原因拥有不同指纹。
项目原有射击链路先从相机中心取远处目标,再让枪口朝这个目标会聚。这个设计能让第三人称准星更容易打中屏幕中心,但也会二次改写表格生成的发射方向。此前被调整的是中间结果,并非最终弹道;后续会聚再次将其拉回固定方向,或叠加与相机—枪口视差有关的偏移。
稳定左下偏移由此得到解释。
最终方案严格限定在测试枪:
- 使用相机方向作为基础射线;
- 在基础射线上只叠加本枪的散布;
- 跳过旧的枪口会聚方向修正;
- 保留项目原有相机、后坐力和其他武器路径不变。
诊断日志同时记录三组量:数据表输出方向、会聚前后差值和最终发射向量。稳定结果必须满足“测试模式开启、会聚差值为零、额外速度方向差为零”。满足这些条件后,网页曲线和运行时弹道才具有相同的比较对象。
前述多轮无效参数调整可以归结为同一原因:
如果调参层不是最终控制层,再精确的参数也只是在给后续覆盖提供更精确的输入。

七、把网页、日志和游戏组成一台仪器
每次修改后都进入编辑器、打一整个弹匣,再凭记忆判断是否更接近参考,效率很低。随机种子、操作误差和帧率波动还会混在一起,让一次偶然较好的弹着看起来像有效修改。为此,我们没有直接做一张“最终工具”,而是随着问题逐步增加,先后做了三个页面。
第一阶段:Recoil Lab 先回答“这组输入大概会画出什么”
最初的 HD2 Recoil Lab 是一个参数预演页。它可以调整弹数、射速、随机种子、Climb、Drift、恢复和散布,同时绘制相机轨迹与逐发着弹点,并按发序连接弹着。它很适合快速排除明显错误:例如纵向爬升过大、横向摆动完全不足,或停火恢复速度不对。
这个页面也经历了几次修正。第一版只有相机轨迹,没有弹着轨迹;补上弹着点后,又发现随机量被重复采样,模拟结果比项目运行时更散。后来我们按真实发射链路收敛采样次数,并默认关闭信息价值较低的辅助曲线。到这一步,页面可以生成候选参数,但仍然无法证明游戏实际执行了同一套逻辑。

*早期 Recoil Lab 的一次中间结果:蓝线为 Climb 相机模型,橙点为逐发弹着,绿虚线为项目相机。明显错位暴露了 HD2 输入字段与项目系数不能逐项直接映射,这不是最终参数。*
第二阶段:Fit Lab 检查运行时究竟在哪一层发生偏差
当项目出现“表已经变化,游戏里却没有散开”以及“弹着持续偏向左下”时,继续调输入页已经没有意义。我们给发射链加入逐发探针,把 Client.log 中的 [RecoilConfig]、[Spread]、[Ballistics] 和 [Impact] 记录交给新的 HD2 AR15 Fit Lab 解析。页面不再负责猜参数,而是把同一发子弹拆成五层查看:
recoil-only:相机与后坐力本身产生的角度;spread-only:散布单独贡献的随机偏移;convergence-only:第三人称枪口向瞄准点会聚造成的改向;final ballistic:真正交给发射逻辑的最终方向;impact:墙面上的实际着弹坐标。
这五层让问题第一次可以被逐发追踪。若 recoil-only 已经变化,而 final ballistic 没变化,说明后续层覆盖了结果;若 final ballistic 正确而 impact 偏离,则应检查距离、碰撞或坐标换算;若 convergence-only 出现固定偏移,就不该继续修改后坐力表。左下偏移最终正是通过这条路径排除散布和后坐力,定位到第三人称会聚层。

*Fit Lab 直接读取实测日志,并在后坐力、散布、会聚、最终发射方向和墙面着弹之间切换。图中 v19 的 30 发样本横向跨度为 7.85 厘米、纵向跨度为 23.55 厘米,且 ConvergenceDelta = 0。*
第三阶段:Final Compare 冻结结论
可调页面适合搜索,不适合作为最终证据。只要滑块或随机种子仍能变化,先前截图就可能无法复现。因此又增加了 HD2 AR15 Final Compare:它不再提供大范围调参,而是固定参考目标、候选版本和判定统计。v18、v19 与 HD2 视频推导目标并列展示,保留横向跨度、纵向跨度、早期爬升和稳定段等结论。

*结算页冻结了参考目标、v18、v19 和机制检查结果。它记录“为何接受这一版”,避免可调页面中的临时状态被误当成最终证据。*
三个页面承担不同职责:Recoil Lab 生成候选,Fit Lab 验证运行时链路,Final Compare 保存结论。网页不能替代游戏,因为它不包含角色动画、枪口视差、真实帧率和输入手感;游戏也不能替代网页,因为肉眼无法准确记住第 17 发相对第 16 发移动了多少。运行时日志把两类证据连接起来。
实际使用时,我们采用以下顺序:
- 从参考录像提取目标包络、初始爬升、稳定段和停火恢复特征;
- 在 Recoil Lab 中快速搜索一组能够生成相似轮廓的候选输入;
- 将候选值导入测试枪,只改变本轮要验证的一个变量;
- 在游戏中保持同一把枪、同一姿态、同一目标墙和同一距离,不压枪并打完整弹匣;
- 将完整
Client.log粘贴到 Fit Lab,先核对样本数,再依次查看 recoil、spread、convergence、final 和 impact; - 只在找到首个分歧层后修改相应控制层,避免拿后坐力参数补偿会聚或 UI 问题;
- 返回游戏确认角色动画、相机反馈和实际操作感,最后把接受版本写入 Final Compare。
距离是这套流程中不能省略的条件。同一角度在不同墙距上会形成不同的厘米跨度,因此所有项目样本固定在约 8.98 米 的测试墙;回灌日志时也不混用其他距离。参考视频中,30 发肩射弹着区域的纵向量级约为画面高度的 2.41%。结合参考画面比例、视场角估计和 8.98 米测试距离,推导出的目标纵向范围约为 19–24 厘米。最终一组 30 发记录的横向跨度约 7.85 厘米、纵向跨度约 23.55 厘米,初始方向对应的角跨度约为水平 0.588°、纵向 1.723°。
这个换算必须带着误差一起读。参考录像没有精确墙距、相机内参和逐发弹孔坐标,所以 19–24 厘米只是从约 13 像素/540 像素画高的观测比例反推的目标带,不是 HD2 的原始配置,更不是逐发真值。7.85 和 23.55 厘米来自项目运行时记录,精度更高,但也只代表一个随机种子下的一组样本。两边可以比较总体量级、爬升形状和包络,不能宣称逐发完全复刻。
该页面最终确定了“接近”的评价维度:
- 不比随机点位逐发一致;
- 比早期爬升斜率;
- 比峰值与稳定段高度;
- 比横向包络;
- 比停火恢复时间;
- 比弹着区域与准星承诺是否一致。
为降低每轮测试的变量数量,体验验证采用固定协议:同一把测试枪、同一目标墙、约 8.98 米固定距离、站立肩射、不进行人工压枪,并连续发射完整弹匣;姿态验证只改变站、蹲、趴这一项。每次测试只回答一个问题。若同时改变武器、距离、姿态和输入,就无法确定结果差异的来源。

八、准星不是装饰,它是弹道的合同
准星看上去是 UI,实际签的是一份弹道合同:它要告诉玩家相机中心在哪里、子弹大致往哪去、当前散布有多大。
弹道基本稳定后,肩射准星仍有数项问题:进入肩射时消失;修复显示后,腰射和肩射一样大;肩射连射时四条准星臂不展开;准星看似居中,弹着点却集中在其左下角。
准星消失并不是资源丢了。旧 HUD 把“瞄准”统一理解成“隐藏腰射准星”。在只有腰射和贴镜两态时,这条规则没问题:一旦瞄准,玩家看到镜内分划,屏幕十字可以退场。现在中间插进了肩射,右键虽然进入瞄准状态,画面仍是第三人称,还需要动态准星。规则没坏,只是它认识的状态已经过期了。
第一版修复直接保证肩射显示,结果误伤腰射显隐;第二版依赖缩放状态判断,又因为缩放和真实视角模式并不一一对应而失效。最终规则回到三态本身:腰射显示腰射准星,肩射显示肩射准星,真正 ADS 才交给镜内 UI。并且这条改动先限定在测试路径,避免在没有完整武器验收时改变全项目 HUD 行为。
最初方案曾考虑直接移动四条准星臂。人工验收重新确认了边界:四条准星臂形成的中心应保持在屏幕中心,错误弹道应在发射链路中修正,而不应通过移动 UI 进行补偿。
这句话把责任划得很清楚:
- 准星中心代表玩家的观察与瞄准中心;
- 准星展开代表当前可能的弹着范围;
- 弹道必须兑现这两个承诺;
- 不能让 UI 去追偿射线链路的偏差。
因此左下偏移最终在弹道方向层修,而不是给准星加位置补偿。修完后再处理准星自身;以下均为当前测试枪的工程参数:
- 腰射保持较大的基础展开;
- 肩射保持可见,不再被“进入瞄准即隐藏”的旧逻辑误伤;
- 肩射静态半角约 0.90°;
- 连射额外展开约 0.45°,总上限约 1.35°;
- 每发产生展开冲量,停火后连续收拢,而不是开关式跳变。
“肩射和腰射一样大”是另一笔总量账。两个状态虽然读了不同配置,最后却都被同一个最小像素尺寸钳住,画面上当然没有差异。解除钳位后,肩射又小得几乎只剩一个中心点。我们没有继续按像素拍脑袋,而是把准星臂到中心的距离换算成角度,拿它和弹道散布用同一单位对账。分辨率会改变像素,角锥覆盖的世界范围不会跟着乱跑。
动态展开还得跟着每一发走。只在“开火开始”时加一次偏移,结果就是第一发张开,后面纹丝不动;只读表里的基础散布,也表达不了后坐力进入稳定段后的额外不确定性。定稿模型改成每发给展开量一次冲量,随后按帧连续衰减,并设置总角度上限。这样四条准星臂会告诉玩家枪正在失稳,松开扳机后也能看见它慢慢收回来。
最后补上站、蹲、趴差异。当前测试枪选择的工程比例是 1.0 / 0.6 / 0.4,同时作用于肩射后坐力和准星总锥角:
| 姿态 | 比例 | 静态准星 | 连射上限 |
|---|---|---|---|
| 站立 | 1.0 | 0.90° | 1.35° |
| 蹲姿 | 0.6 | 0.54° | 0.81° |
| 趴姿 | 0.4 | 0.36° | 0.54° |
第一版只缩放额外的 0.45°,三种姿态的上限分别为 1.35°、1.17°、1.08°,视觉差异很小。后续改为缩放总锥角,姿态也直接读取角色真实的站、蹲、趴状态,不再依赖短暂动画标签推断。
这与 ADS 问题具有相同机制:玩家感知的是合成后的总量,仅缩放其中一层未必会显著改变最终画面。

*项目画面 D:蹲姿肩射保持相同的瞄准中心,但通过机位与稳定性比例表达更低的姿态。*

*项目画面 E:趴姿继续收紧肩射稳定性;右下角与底部运行信息已做灰色遮挡。*

*项目画面 F:连续开火时,准星臂围绕屏幕中心展开,弹着点落在它承诺的区域内;UI 不再追着错误射线移动。*
九、三种瞄准状态需要不同的后坐力模型
相机已经分清腰射、肩射和贴镜。开火反馈如果还共用一套系数,切状态就只是在换构图,枪的控制感不会跟着变。
最终测试枪采用三态分流:
- 腰射:较大的准星和散布,信息重点是方向而非精确点;
- 肩射:保留第三人称可读的上爬、横向摆动和回正,是这次参考对齐的主体;
- ADS:更小的画面踢升,接近每发微量永久爬升,不套用肩射那条明显回正曲线。
状态判断不再使用“是否缩放”等代理信号,而是直接读取第一人称与贴镜状态。缩放、肩射推进和贴镜可能在同一段输入中重叠,代理信号会在边界帧产生错误判定。
作用域也必须钉死:三态分流和参考步枪参数只落在测试枪路径,其他武器继续走项目原逻辑。这次要跑通的是方法和管线,不是趁相机收尾顺手重写整个武器库。
“只影响测试枪”不能靠一句条件判断口头保证。我们从四个层面核对作用域:
- 数据层只有测试枪关联到新的后坐力与散布行;
- 代码层的弹道旁路同时检查专用开关和武器身份,任一不满足就回到原路径;
- UI 层的肩射显隐与动态锥角只在对应状态和武器上启用;
- 默认配置保持关闭,旧资产没有新增必填字段也能维持原行为。
我们又拿一把普通项目武器做反向验收:同一场景下,它的发射方向仍经过原会聚链,旧后坐力表仍能命中,准星显隐和展开也没变。正向测试只能证明新功能能跑,反向测试才知道它有没有漏到别人家里。项目里已有大量武器内容时,后一个问题往往更要命。
后续产品化路径由此明确:先用一把测试枪验证机制、工具和验收协议,再将“参考输出目标”替换为各武器自身的数据。测试枪的体验特征不能写成全局常量,也无须仅因获得完整武器清单就一次性填充整个数据库。原型阶段负责证明管线,内容生产属于下一阶段。
十、最后一公里:运行正确还不等于交付正确
功能通过体验验收后,仍存在一项交付风险。代码已经提交、表格已经导入,版本控制中的已打开文件也可能为空,但另一台机器仍未必能获得相同数据。
原因是数据存在三种形态:
- authored CSV:人维护的源数据;
- exported CSV:从引擎资产导出的核对副本;
- DataTable 资产:运行时真正读取的内容。
只检查当前已签出的文件,会漏掉本地已变化但尚未纳入变更列表的资产。最终我们额外执行了工作区对账,找出那份未登记的 DataTable 资产;再把 authored CSV、exported CSV 和资产导出逐行比对,112 行关键字段零差异后,才进入新的变更提交。
它偏偏发生在“功能已经可以玩”之后,所以最容易被跳过。只提交代码,另一台机器会拿着新逻辑读旧数据;只提交 CSV、漏掉运行资产,本机缓存又可能让一切看起来正常。
我们的收尾检查因此固定为四问:
- 源 CSV 是否包含最终值;
- 引擎资产冷读后是否返回同样的值;
- 导出 CSV 是否与源 CSV 的关键字段逐行一致;
- 工作区对账是否还有未登记的新增、修改或删除。
这里所谓“冷读”,就是不信刚导入完的内存状态,重新从资产读一次。它和前文记录最终发射向量是同一条原则:中间步骤说成功不算,最后使用它的地方读对了才算。
从那以后,“完成”多了一条标准:
本机运行正确只是运行时真相;源码、源数据、生成资产和版本控制四者一致,才是团队可复现的交付真相。

十一、时序响应的验收标准
至此,TPS 相机主线具备收尾条件。交付物不再只是可运行的第三人称镜头,而是一组可复查的结果:
- 腰射、肩射、ADS 三态输入和切换行为确定;
- 举枪约 0.20 秒、收枪约 0.25 秒、ADS 双向硬切;
- 位置跟随恢复为真实跨帧插值,并通过探针验证;
- 测试枪三态后坐力分流,不影响其他武器;
- 肩射弹道按参考步枪的输出包络对齐;
- 准星中心、动态展开与真实弹道一致;
- 站、蹲、趴拥有可读的肩射稳定性差异;
- 代码、表格、资产和两个版本库完成对账。
回看上、下两篇,我们最初写下的公式是:
体验 = 功能 × 数据 ← 测量
这两周又给它补了一层约束:
手感 = 多套反馈系统在同一时间轴上的一致性。
功能实现决定系统是否运行,配置数据决定响应幅度,测量结果定义目标范围。时序验收需要同时检查相机、后坐力、弹道、动画和 UI,避免各子系统独立正确而合成结果不同步。
工具随问题逐步扩展:先有逐帧差分、屏幕指纹、胶片带和地标追踪,随后增加位置探针、开火日志和可回灌运行时数据的网页实验台。工具不能代替体验判断,但能把“哪里不像”缩小到可验证的范围。这次工作留下的不仅是测试枪和相机参数,也包括一套可以复用于其他体验问题的实验基础设施。
最终结论仍由人工体验验收确定。工具负责缩小搜索范围,数据负责排除错误判断,代码与配置负责保证结论可以复现。
十二、AI 协作复盘
本次协作可以从四个方面复盘。
AI 的有效贡献
AI 将分散的观察与证据连接起来:分析录像、追踪调用链、整理数据、建立预览工具,并将运行时日志回灌比较。原本分布在程序、技术策划和测试环节的信息由此保留在同一条证据链上。其直接贡献是缩短了从现象描述到可验证假设的距离。
AI 的主要误判
最典型的错误不是数值计算,而是控制层定位。AI 曾连续调整数据表,却没有先证明表格输出是否为最终发射方向;在某轮结果没有变化后仍继续增加参数,随后才确认运行时并未进入预期数据路径。AI 能在既定模型中快速收敛,但错误模型也会使无效方案迅速复杂化。
人工判断承担的职责
关键纠偏均来自人工体验判定:先右后左的轨迹不符合参考;缺少判别价值的辅助线应当移除;弹着点偏向准星左下时应修正弹道,而不是移动四条准星臂;多轮参数无效后,应转而验证运行时是否读取目标数据表。这些判断持续收缩问题边界。AI 可以提高测试覆盖率,但不能替代实际操作与最终体验验收。
验证流程的修正
每次错误都调整了后续验证顺序:先检查作用域和最终数据消费者;用日志证明链路后再调整参数;先在网页中比较输出特征,再进入游戏验证体验;分别记录准星、弹道和相机结果,最后进行合成验收。提交前还需核对源数据、资产和版本库。
本次工作的价值并不在于 AI 一次得出正确答案,而在于每次错误之后,项目都新增了一项工具、一条规则或一份证据。后续处理载具镜头、重武器瞄准或受击反馈时,可以继续复用空间构图、反馈时序和验证工具,不必重新从主观描述开始。
尾声:两篇之外,还有什么
上下两篇覆盖的是角色基础移动和步枪射击场景下的 TPS 相机体验闭环,并不试图列举完整游戏中的全部相机功能。贴墙与狭窄空间中的精细碰撞恢复、已完成原型但未继续产品化的换肩、依赖敌人与伤害链的受击反馈,以及重武器、载具、观战和死亡等特殊状态,都被明确排除在本阶段范围之外。完整武器库的逐枪差异、手柄与辅助瞄准、不同帧率和屏幕比例下的舒适性验收,也适合后续单独讨论。
这些内容不是“主线完成”之后的遗漏,而是后续专题。届时仍可使用空间构图方法确定机位关系,使用时序响应分析检查各反馈系统的触发与恢复,并继续复用录像、探针、运行时日志和网页实验台。当前留下的是可扩展的验证基础,而不是尚未调整完成的参数。
*至此,TPS 相机改造主线完成。上篇回答“镜头应该在哪里”,下篇回答“所有反馈应该在什么时候发生”;空间构图与时序响应结合后,才是一套能被测量、实现、体验和交付的相机系统。*