这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
《游戏引擎实现原理》2.1 内核单测与假对象
引擎测试的难点不在断言,而在把外部世界换掉:时间、图形 API、磁盘与随机数。本节用 FakeClock、NullRHI、内存文件系统与种子化 PRNG 四类假对象,拼出一个无 GPU、无磁盘、无真实时钟的内核测试台,让同一关卡每次跑出逐位一致的结果。全部代码在 Node 直跑,17 条用例锁住行为。
posts
这里是全站文章的归档入口,下面是按时间倒序排列的全部文章。若想按主题浏览,请从首页的专题分类进入。
引擎测试的难点不在断言,而在把外部世界换掉:时间、图形 API、磁盘与随机数。本节用 FakeClock、NullRHI、内存文件系统与种子化 PRNG 四类假对象,拼出一个无 GPU、无磁盘、无真实时钟的内核测试台,让同一关卡每次跑出逐位一致的结果。全部代码在 Node 直跑,17 条用例锁住行为。
全书的最后一节:给出三条能真正走下去的路——去读 three.js、Bevy、Godot、Filament 这些真实引擎的源码该从哪个文件入手,怎么给开源项目提第一个 PR,以及如何按本书四卷的顺序做自己的引擎并用一个自检脚本量进度。同时明确本书不覆盖的边界:地形流式、网络同步、光追与全局光照、体积云与水体,都指向站内既有文章。
全书收官的第一节,把四卷 60 章拉成一张「一个引擎由哪些原理构成」的全景图:内核的内存、句柄、容器、数学、数据导向、ECS、任务与反射,渲染的 RHI、剔除、材质、光照、帧图与后处理,子系统的资源、动画、物理、音频、输入与编辑器,工程端的构建、测试、性能、跨端与裁剪。每一章都给出直达代表节的链接,并用本机实跑的小工具把 helio 的真实体量盘出来。
《微光岛》不可能把整包都塞进首屏。本节写一个分包器:入口 chunk 只装从启动入口静态可达、且不穿过懒加载点的模块,其余按懒加载根切成独立 chunk。实测首包 19517 字节(gzip 6558)、整包 29212 字节;不上提共享依赖则整包膨胀到 47439 字节。
同一张 256×256 地形贴图,在显存里是 262144 字节的裸 RGBA,无损 PNG 压到 64992 字节,BC1 块压缩只留 32768 字节但 PSNR 掉到 37 dB。本节用 Node 从零实现 PNG 编码器与 BC1 编解码,量出三种产物的真实体积、压缩率与解码耗时,全部本机实跑。
卷四开篇,先把前三卷的 helio 引擎变成一个可分析的产物:用 module-graph 扫出 187 个模块的依赖图,量出「源码 → 打包 → 压缩」三段真实体积,再用符号级 tree-shaking 删掉入口用不到的顶层导出。全部代码在 Node 直跑,拼出来的 bundle 与原始 demo 逐位相同。
以 arch-lab 订单系统的七个部署单元为例,说明哪些模块必须同进程、哪些可以独立发布,单点与故障域如何登记;给出可运行的 deploymap 校验器,把未声明单点、无超时或无降级的跨单元强依赖、故障域重叠变成 go test 能抓住的违规,并用同步闭包计算一次发布的影响面。
以 Book 的字段设计为线索,讲清八种基本类型的范围与默认值、什么时候该用 int 而不是 Integer、ISBN 为什么必须用 String;再拆开装箱拆箱、Integer 缓存、== 与 equals 的差异,用真实 NPE 和 128 比较结果说明包装类型最容易踩的三个坑。
公平与手感之间的取舍。本节讲延迟补偿的常见做法与服务端回滚判定所需的客户端配合,把「双人竞速各跑各的」讲透——纯计时不需要补偿,只有碰撞干扰才需要,并给出带死区与上限的 L1 补偿决策函数、配套单测,以及一张把零补偿到无上限动态补偿逐项对比的公平与手感权衡表。
延迟、掉线、重连该怎么告诉玩家,以及哪些网络数据不该给玩家看。本节给出网络质量档位到图标与文案的映射表、提示的时机与频率控制、无障碍与本地化考虑,并落到一个订阅会话状态与诊断数据的 L2 UI 组件,以及一个可单测、覆盖多档位边界的 L1 档位映射函数。
前几章把插值与预测写成了可测的纯逻辑,本节把它接到 Cocos 节点与帧循环:讲清逻辑 60 Hz 定点与渲染浮动帧率的分工,远端玩家如何用插值位置驱动 setPosition、用插值速度切换动画,为什么特效必须由服务端事件触发而非状态推断,并给出 L1 纯函数插值器与 L2 组件脚本。
客户端侧的加密配合与它的边界:wss 传输层加密在 H5、微信小游戏、原生三端的支持情况与证书要求,消息校验和与 HMAC 能防网络中间人篡改、却防不了本地改客户端,客户端该做与不该做的一整张职责清单,最后回到「真正的裁决在服务端」这条底线。
客户端不可信,所以这一节校验的是服务端下发的快照:字段范围、时序合理性、序号连续性、与本地预测的偏差四类检查,配上接受、平滑修正、丢弃、上报四种处理策略,并明确客户端校验只保可用性与健壮性、不阻止作弊,最后给出可跑的快照校验器、假传输层与 vitest 单测。
把《方块冲刺》的每个游戏事实逐一归类到权威方:位置、速度、输入、计时、得分、掉落、胜负各自归谁管、客户端被改会怎样,给出「客户端只发意图、不发结果」的原则,讲清客户端预测为什么不是客户端权威,再用一张权威边界表与可跑的单测把边界钉进协议与代码。
线上卡顿与不同步不能靠猜。本节先给出一张从症状到原因的排查表(橡皮筋、远端瞬移、逐渐漂移、周期性卡、特定网络必现),再说明客户端该落哪些日志、怎么采样控制体积,并用纯 TS 写出固定容量的环形日志缓冲与按帧号关联输入和快照的追踪,最后把线上抓到的网络序列喂回 7.1 的模拟器复现。
机器人压测不是拿真玩家去撞服务端,而是把客户端逻辑层抽出来,在 Node 里同时驱动成百上千个无渲染的机器人,用它们压自己这套模拟与消息处理。本节给出机器人客户端与脚本化行为的纯 TS 实现、只回最小快照的假服务端测试替身、用 vitest 断言规模下的单帧耗时预算,并说明压测结论该怎么写才可信。
本地复现线上卡顿的前提,是能造出一模一样的弱网。本节把弱网拆成延迟、抖动、丢包、乱序、带宽与突发中断六种病,给出一个可配置、可脚本化的弱网 Transport 装饰器,用固定随机种子保证可复现,并用 vitest 断言丢包率与延迟分布落在设定区间,最后列出诊断面板该采集的指标。
观战与回放都不产生输入,只把同一场比赛在本地重演。本节对比观战与参战的数据流差异,讲观战为何只需要插值、不需要预测,说明回放该录输入流与随机种子而非状态,用纯 TS 写出可单测的回放器(记录加重演、关键帧快照支持拖动进度),并估算一局录像的体积。
拿到 roomId 之后,客户端要跟住房间从创建到销毁的整条状态链。本节映射房间的等待中、准备中、进行中、结算中、已销毁五个状态到客户端状态机,处理玩家上下线与对手离开,讲清房间配置(赛道、规则、随机种子)为何必须由服务端下发,并用纯 TS 写出可单测的房间状态机与配置同步。
匹配是联机第一关。服务端的匹配算法不在本书范围,本节只讲客户端在匹配里要做什么:拆开排队、已匹配待确认、确认中、已进入、取消这套客户端状态机,给出进队、匹配成功、确认、取消四条消息的字段与方向,用假传输层写出可单测的匹配客户端,并处理重复提交与确认超时两个真实坑。