附录 C 全书代码、配置与数据集索引

《小游戏开发实战》卷二《引擎、实现与体验打磨》的复现索引:按 16 章列出 pebble/ 下全部 config / sim / core / web 文件,写清卷二工具链的 e<章号>_ 前缀约定(与卷一的 ch 前缀区分,避免 node --test 通配符交叉匹配)、环境速查与六层可运行性口径(S/P/W/D/X/B)的逐层复现命令,以及一键复现与排错顺序。

这一页解决一个问题:卷二里出现的每一段代码、每一份配置、每一个数据集,在 pebble/ 里叫什么、放在哪、怎么跑。 它是一张可检索的清单,也是一份复现手册。

一、这份索引解决什么

卷二的每一节都至少带一个 S / P / W 层的可运行产物。产物多了就需要一张总表,回答三件事:

  1. 这个产物叫什么名字、放在哪个目录——按章列出 pebble/ 下的文件,命名规则统一,一眼能定位。
  2. 它属于哪一层、怎么验证——六层口径(S / P / W / D / X / B)各自的复现命令不同,这一页把它们并排写出来。
  3. 它依赖什么环境——两个 python3、Node 26、Playwright 复用,任何一处不对都会让「代码看起来错了」,其实只是环境错了。

贯穿全书的仍是《合成小岛》(merge-island)与工具链 pebble。卷二沿用卷一的两条主张:一份 config,三种消费、一份逻辑,两种宿主;config/ 是唯一真源,Python 仿真、TS 内核、浏览器原型读同一份数字。

二、目录约定:为什么卷二用 e<章号>_ 前缀

这是卷二最容易踩的坑,先讲清楚。

卷一的工具链文件用 ch00–ch15 前缀(如 config/ch06_loop.json、sim/ch06_loop.py、core/test/ch06_merge.test.ts)。卷二一律改用 e<章号>_ 前缀(两位章号,如 e01、e04、e16):

config/e04_atlas.json          # 卷二的配置
sim/e04_atlas.py               # 卷二的仿真
core/src/e04/…                 # 卷二的内核源码目录
core/test/e04_atlas.test.ts    # 卷二的测试
web/build_e04.mjs              # 卷二的单文件 HTML 构建脚本
web/verify_e04.mjs             # 卷二的 Playwright 无头验收

为什么必须换前缀:node --test 接收的是 glob,不是目录。如果卷二继续用 ch<章号>_,那么无论跑 node --test 'core/test/ch*.test.ts'(卷一)还是跑卷二的用例,通配符都会同时匹配到两卷的测试文件,一条命令里混进另一卷的断言,输出就不可信了。换成 e<章号>_ 之后:

  • 卷一:node --test 'core/test/ch*.test.ts'
  • 卷二:node --test 'core/test/e*.test.ts'

两个 glob 互不重叠。注意还要带上两位章号与下划线(e04_ 而不是裸 e*):裸 e* 会误匹配 core/test/economy.test.ts 这种既有文件,所以复现命令里要写全 e04_*.test.ts 这样的精确前缀。

三、按章索引(16 章)

下表把卷二 16 章各自的产物按目录列出。<NN> 是两位章号(01–16),<name> 是该章的文件名(英文 kebab),同一个 <name> 在 config/、sim/、core/test/ 之间保持一致,便于对照。

章主题configsimcore/srccore/testweb
1引擎与框架选型config/e01_*.jsonsim/e01_*.pycore/src/e01/core/test/e01_*.test.tsweb/build_e01.mjs · web/verify_e01.mjs
2工程骨架与构建管线config/e02_*.jsonsim/e02_*.pycore/src/e02/core/test/e02_*.test.tsweb/build_e02.mjs · web/verify_e02.mjs
3渲染与适配config/e03_*.jsonsim/e03_*.pycore/src/e03/core/test/e03_*.test.tsweb/build_e03.mjs · web/verify_e03.mjs
4资源与素材管线config/e04_*.jsonsim/e04_*.pycore/src/e04/core/test/e04_*.test.tsweb/build_e04.mjs · web/verify_e04.mjs
5游戏循环与状态机config/e05_*.jsonsim/e05_*.pycore/src/e05/core/test/e05_*.test.tsweb/build_e05.mjs · web/verify_e05.mjs
6输入与交互实现config/e06_*.jsonsim/e06_*.pycore/src/e06/core/test/e06_*.test.tsweb/build_e06.mjs · web/verify_e06.mjs
7物理与碰撞config/e07_*.jsonsim/e07_*.pycore/src/e07/core/test/e07_*.test.tsweb/build_e07.mjs · web/verify_e07.mjs
8数据、存档与反作弊config/e08_*.jsonsim/e08_*.pycore/src/e08/core/test/e08_*.test.tsweb/build_e08.mjs · web/verify_e08.mjs
9对象池与内存管理config/e09_*.jsonsim/e09_*.pycore/src/e09/core/test/e09_*.test.tsweb/build_e09.mjs · web/verify_e09.mjs
10平台能力适配层config/e10_*.jsonsim/e10_*.pycore/src/e10/core/test/e10_*.test.tsweb/build_e10.mjs · web/verify_e10.mjs
11UI 系统与界面实现config/e11_*.jsonsim/e11_*.pycore/src/e11/core/test/e11_*.test.tsweb/build_e11.mjs · web/verify_e11.mjs
12动效与手感打磨config/e12_*.jsonsim/e12_*.pycore/src/e12/core/test/e12_*.test.tsweb/build_e12.mjs · web/verify_e12.mjs
13新手引导实现config/e13_*.jsonsim/e13_*.pycore/src/e13/core/test/e13_*.test.tsweb/build_e13.mjs · web/verify_e13.mjs
14性能优化config/e14_*.jsonsim/e14_*.pycore/src/e14/core/test/e14_*.test.tsweb/build_e14.mjs · web/verify_e14.mjs
15测试与质量保障config/e15_*.jsonsim/e15_*.pycore/src/e15/core/test/e15_*.test.tsweb/build_e15.mjs · web/verify_e15.mjs
16工程化与协作config/e16_*.jsonsim/e16_*.pycore/src/e16/core/test/e16_*.test.tsweb/build_e16.mjs · web/verify_e16.mjs

读法:想复现第 4 章某节的 S 层仿真,就去 sim/e04_*.py 里找对应的脚本;想跑它的 P 层测试,就 node --test 'core/test/e04_*.test.ts';想看它的 W 层原型,就 node web/build_e04.mjs 产出 HTML 再 node web/verify_e04.mjs 验收。同一章的 config/ / sim/ / core/ / web/ 四类文件用同一个 <name> 串联,这是「一份 config 三种消费」在文件系统上的体现。

四、分层产物索引

按可运行性层级看,卷二的产物分布如下。同一章可能同时出现多个层级:

层典型文件产物是否可命令行复现
S 仿真sim/e<NN>_*.pyout/e<NN>_*.json / .csv / .svg是
P 内核core/src/e<NN>/… + core/test/e<NN>_*.test.tsnode --test 通过 / 失败是
W 网页web/build_e<NN>.mjs + web/verify_e<NN>.mjsweb/dist/e<NN>.html + out/shots/*.png是
D 静态config/e<NN>_*.json(schema)、兼容矩阵、检查清单schema / lint 校验结果是
X 不可复现正文标注段真实平台后台、真机帧率、审核结果否(需真实业务环境)
B 基准sim/*_bench.pyout/*.json(软告警)是

数据集在这里指两类:① config/ 下的配置表(e<NN>_*.json,全整数、禁浮点,是设计的唯一真源);② out/ 下仿真产出的 *.csv(逐行数据,可导入 pandas 复核)与 *.json(结构化结果)。W 层的 out/shots/*.png 是无头验收的截图证据。

五、环境与复现速查

项值说明
Python(S 层)3.14.6,/opt/homebrew/bin/python3带 numpy 2.5.1 / pandas 3.0.3 / PIL 12.3.0
Python(系统)3.9.6,/usr/bin/python3无 numpy/pandas,正文命令一律写全路径
Node26.5.0原生跑 TypeScript,strip-only,禁 enum / namespace / 参数属性 / 装饰器
Playwright1.59.1,Chromium 已缓存装在 /opt/homebrew/lib/node_modules,用 NODE_PATH + createRequire 复用
matplotlib / scipy未安装图表走纯 Python SVG(xml.etree)
tsc / tsx / vitest / npm 包均不使用无 package.json、无 npm install

两个高频陷阱,先记住:

  1. node --test <目录> 不发现 .ts——必须传 glob:node --test 'core/test/e04_*.test.ts',写目录会报找不到模块。
  2. NODE_PATH 对 ESM import 无效——W 层脚本里必须 createRequire(import.meta.url) 之后 require("playwright"),不能写 import { chromium } from "playwright"。

六、六层逐层复现命令

每一层都有固定的复现命令。<NN> 换成章号(如 e04),<name> 换成该章的文件名:

层命令(在 pebble/ 下执行)
Sfor f in sim/e<NN>_*.py; do /opt/homebrew/bin/python3 "$f" --config config/ --out out/; done
Pnode --test 'core/test/e<NN>_*.test.ts'
Wnode web/build_e<NN>.mjs && NODE_PATH=/opt/homebrew/lib/node_modules node web/verify_e<NN>.mjs web/dist/e<NN>.html
D/opt/homebrew/bin/python3 sim/ch00_validate_config.py --config config/ --schema config/ch00_schema.json
X无命令——真实平台后台 / 真机帧率 / 审核结果需真实业务环境,正文每处已标注
Bfor f in sim/*_bench.py; do /opt/homebrew/bin/python3 "$f" --config config/ --out out/; done

为什么要写 for f in …; do …; done 而不是 python3 sim/e04_*.py:shell 会把通配符展开成多个文件名传给同一个 python3,只有第一个脚本真的执行,其余被当成参数吃掉(卷一第 9 章踩过这个坑)。逐个跑或用 for 循环才安全。node --test 自己展开 glob,不受影响。

七、一键复现与排错

复现任意一节的标准动作,是把该节的 file: 块还原到 pebble/<file>(工作区已就绪),然后跑它 verify: 里那条命令。下面这段 S 层脚本先把环境确认一遍,任何一层不对它都会报出来:

# file: sim/ch00_env_check.py
# tier: S
# verify: /opt/homebrew/bin/python3 sim/ch00_env_check.py
"""环境自检:确认《小游戏开发实战》三卷需要的运行时都在,并打印 pebble 的能力阶梯。

本机有两个 python3,不要混:
  /opt/homebrew/bin/python3 = 3.14.6(带 numpy / pandas / PIL),S 层仿真一律用它;
  /usr/bin/python3          = 3.9.6(系统自带,无 numpy/pandas),只能跑最朴素的脚本。
"""

from __future__ import annotations

import os
import shutil
import subprocess
import sys

EXPECT_PY = "/opt/homebrew/bin/python3"


def main() -> int:
    ok = True

    # /opt/homebrew/bin/python3 是符号链接,比较时解析到真实二进制再判断
    real = os.path.realpath(sys.executable)
    print(f"python     {sys.version.split()[0]}  ({real})")
    if real != os.path.realpath(EXPECT_PY):
        print(f"           注意:正文脚本一律用 {EXPECT_PY},当前解释器不同")

    try:
        import numpy
        import pandas

        print(f"numpy      {numpy.__version__}")
        print(f"pandas     {pandas.__version__}")
    except ImportError as e:  # noqa: BLE001
        ok = False
        print(f"FAIL 缺依赖:{e}(S 层需要 numpy 与 pandas)")

    node = shutil.which("node")
    if not node:
        ok = False
        print("FAIL node 未安装(P 层需要 Node 26 或更高)")
    else:
        ver = subprocess.run([node, "-v"], capture_output=True, text=True).stdout.strip()
        major = int(ver.lstrip("v").split(".")[0])
        note = "" if major >= 26 else "  (低于 26,原生 TypeScript 不可用)"
        print(f"node       {ver}{note}")
        ok = ok and major >= 26

    print("pebble 能力阶梯:S 仿真 / P 内核 / W 网页 / D 静态 / X 不可复现 / B 基准")
    print("OK 环境就绪" if ok else "FAIL 环境不满足")
    return 0 if ok else 1


if __name__ == "__main__":
    raise SystemExit(main())

本机实跑输出:

python     3.14.6  (/opt/homebrew/Cellar/python@3.14/3.14.6/Frameworks/Python.framework/Versions/3.14/bin/python3.14)
numpy      2.5.1
pandas     3.0.3
node       v26.5.0
pebble 能力阶梯:S 仿真 / P 内核 / W 网页 / D 静态 / X 不可复现 / B 基准
OK 环境就绪

数字对不上时的排错顺序:

  1. 解释器对吗? 用了系统 3.9.6 会在 import pandas 处报 ModuleNotFoundError,看起来像「代码错了」,其实是解释器错了。命令一律写 /opt/homebrew/bin/python3。
  2. node 版本对吗? 低于 26 就没有原生 TypeScript,.ts 直接跑不起来。
  3. 前缀对吗? 卷二是 e<NN>_,不是 ch<NN>_。写错前缀会匹配不到文件(空跑)或误匹配另一卷。
  4. 配置被改过吗? 这正是「一份 config 三种消费」该有的行为——改 config/e04_*.json 里的参数,sim/、core/、web/ 三处结果都会跟着变。
  5. 是不是「同机相对量级」? 正文标了「同机相对量级,绝对数值不可移植」的地方,绝对值依赖机器,只有相对关系可移植。
  6. 还不对,那就是书错了。 请告诉我具体的节号与数字。

环境口径与全部实跑命令另见卷一的附录 A 。回到卷二目录页 。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「minigame」更多文章

  1. 附录 F:全书公式、参数与数据集索引
  2. 9.3 同意管理与数据出境
  3. 9.2 COPPA 与儿童向游戏的限制