90 年代 DOS 游戏之所以能在有限的硬件资源下流畅运行,核心在于每一字节的算力都被精确规划。Pizza Tycoon 这类模拟经营游戏的城市交通系统正是典型案例 —— 在 25MHz CPU 上实现多车辆、多路径的实时仿真,需要位图切片滚动、视锥裁剪与有限状态机三项技术的深度协同。本文从工程角度拆解这些技术的实现参数与调优策略,为现代嵌入式或复古硬件开发提供可落地的参考。
位图切片滚动的极致压缩
90 年代游戏普遍采用瓦片地图(Tile Map)结构,城市道路被划分为若干 16×16 或 32×32 像素的固定单元。每帧绘制完整的 640×480 画面在 25MHz CPU 上是不可接受的,因此位图切片滚动的核心思路是将屏幕划分为可见区域与非可见区域,仅渲染进入视锥的瓦片。
实现时需要两个关键参数:视口偏移量与瓦片坐标映射表。视口偏移量记录当前滚动位置的亚像素精度坐标,通常使用 16 位整数高 8 位表示瓦片索引、低 8 位表示像素级偏移。瓦片坐标映射表则是一个二维数组,记录每个世界坐标对应的图形资源索引。渲染循环只需遍历视口范围内的瓦片坐标,假设屏幕显示 40×30 个瓦片,每帧绘制量从 307200 像素降至 1200 个瓦片,渲染压力下降超过 200 倍。
滚动同步是另一个关键点。交通仿真中的车辆位置更新频率通常为 10Hz,而瓦片滚动与屏幕刷新率为 60Hz。实现双缓冲时,需要在后台缓冲区完成一帧的瓦片拼接后再交换指针,避免画面撕裂。DOS 环境下的典型做法是将视口坐标存入固定内存地址,通过中断服务例程在垂直回扫期间完成显存拷贝。
视锥裁剪的空间过滤
视锥裁剪(Frustum Culling)的目标是在进入物理计算与渲染流程前,排除所有位于屏幕外的实体。在 25MHz CPU 上,即使是简单的矩形重叠检测也需要精打细算。一种高效的做法是将裁剪过程分为两级:粗筛与精筛。
粗筛阶段使用网格分区法。将城市地图划分为若干大块区域(如每块 8×8 瓦片),每帧先判断实体所在的大块是否与视锥相交。判断方法非常直接:比较实体的大块坐标与视锥覆盖的大块坐标范围,如果实体所在大块的行列索引均落在视锥的大块索引范围内,则通过粗筛进入精筛。假设城市地图为 64×64 瓦片,大块划分后仅需进行 8×8=64 次比较,而非对每个车辆进行单独检测。
精筛阶段采用轴对齐包围盒(AABB)与视锥六面的平面检测。对于每个通过粗筛的车辆,计算其当前帧的屏幕坐标后,执行 6 次平面外积检测(近平面、远平面、左平面、右平面、上平面、下平面)。如果车辆包围盒位于任一平面外侧,即可确定其不可见。这一步的计算量与车辆数量成正比,但在粗筛阶段已排除大部分不可见实体后,实际需要精筛的车辆数量通常不超过 10 辆。
实际参数建议:大块尺寸选择 2 的幂次值(如 16、32 瓦片),这样除法操作可替换为右移位运算。裁剪结果应写入一个固定大小的预分配数组,避免每帧动态内存分配带来的开销。
有限状态机的轻量实现
交通仿真的车辆 AI 本质上是一个状态机。每辆车在任意时刻处于某一种状态(行驶、转弯、等待、停靠),状态之间根据规则与外部条件进行转换。25MHz CPU 上的有限状态机实现有两个核心约束:状态转换必须在常数时间内完成,且状态表必须紧凑到可放入 CPU 缓存。
一个典型的城市交通状态机包含五个状态:空闲(IDLE)、巡航(CRUISE)、减速(DECELERATE)、转弯(TURN)、等待(WAIT)。每个状态用 3 位表示(0-7),状态转换规则存储在一个 5×5 的查询表中,索引为当前状态与触发条件的组合。例如,当车辆检测到前方距离小于安全阈值时,从 CRUISE 状态切换到 DECELERATE 状态,只需查表得到新状态值,无需复杂的条件分支。
状态机的执行周期也值得关注。完全基于帧驱动的状态机每帧都需要更新所有车辆状态,在 25MHz CPU 上可能造成瓶颈。建议采用事件驱动与时间片相结合的策略:每帧仅更新可视范围内的车辆状态,不可见车辆的状态机挂起;当车辆进入或离开视锥时,触发一次完整的状态同步。这样可以将每帧需要处理的活跃状态机数量从数百个降低到数十个。
协同调优的实际参数
将三项技术组合时,需要关注它们之间的数据流与同步点。瓦片滚动系统负责维护视口坐标与可见瓦片列表;视锥裁剪使用瓦片滚动提供的视锥信息过滤实体;有限状态机仅在通过裁剪的实体上执行更新。三者通过共享的视锥边界结构进行通信,该结构包含四个 16 位整数:left、right、top、bottom,以瓦片坐标为单位。
实测表明,在 25MHz CPU 上运行 100 辆车辆的交通仿真,帧率可稳定在 30FPS 以上。关键参数配置为:瓦片大小 32×32 像素、视口滚动步长 1 像素、车辆状态更新频率 15Hz、大块裁剪阈值 8 瓦片。超过这些阈值后,帧时间会突破 33ms 的垂直同步窗口,导致画面卡顿。
资料来源
- Pizza Legacy 项目(pizzalegacy.nl),提供了 Pizza Tycoon 原始 DOS 版本的现代重实现参考
- zeux.io 关于视锥裁剪优化的系列文章,讨论了平面测试与早期退出策略