333. 将 PPU 逻辑名称表转换为不透明度掩码

从一个所选的逻辑 PPU 名称表构建不透明度掩码。

333 / 356 · tests/chapter_13_scrolling/test_333_ppu_logical_nametable_to_opaque_mask.py

待更新文件

emulator/rendering/ppu_background_renderer.py

参考

https://www.nesdev.org/wiki/PPU_nametables

此步骤存在的原因

现有的辅助函数构建了用于精灵优先级和 sprite-zero-hit 检测的掩码,但最初只读取逻辑名称表 $2000。水平滚动还需要属于相邻逻辑名称表的掩码。

兼容性

省略 base_nametable_addr 仍然会选择 $2000,因此在有意进行视口集成之前,现有的 Console 和 sprite-zero-hit 调用方仍然有效。

不透明度输入

  • 来自所选逻辑名称表的 960 个图块 ID
  • 由 PPUCTRL 第 4 位选择的背景图案表

不透明度不使用属性字节、调色板 RAM 或最终 RGB 颜色。

范围之外

  • 组合左右掩码
  • 帧缓冲区渲染
  • 与 Console 集成
  • sprite-zero-hit 视口集成
  • 垂直滚动

完整示例实现

# emulator/rendering/ppu_background_renderer.py

def ppu_background_to_opaque_mask(
    ppu: PPU,
    # --- NEW LINE: OPTIONAL LOGICAL NAMETABLE SELECTION ---
    base_nametable_addr: int = BASE_NAMETABLE_ADDR,
) -> BackgroundOpaqueMask:
    # --- NEW BLOCK: REJECT NON-NAMETABLE BASE ADDRESSES ---
    if base_nametable_addr not in LOGICAL_NAMETABLE_BASE_ADDRS:
        raise ValueError(
            "Logical nametable base address must be $2000, $2400, $2800, $2C00"
        )

    nametable_bytes = bytes(
        # --- UPDATED LINE: READ FROM THE SELECTED NAMETABLE ---
        ppu.ppu_bus.read(base_nametable_addr + offset)
        for offset in range(NAMETABLE_SIZE)
    )

    ...
    # Everything remains the same below this point.

运行本课

uv run pytest tests/chapter_13_scrolling/test_333_ppu_logical_nametable_to_opaque_mask.py -v