300. 解码精灵条目

从 OAM 字节解码一个精灵条目。

300 / 356 · tests/chapter_09_sprite_rendering/test_300_decode_sprite_entry.py

需要更新的文件

emulator/rendering/sprite_renderer.py

为什么需要这一步

上一步定义了 SpriteEntry。现在我们添加一个小型解码器,将原始 PPU OAM 字节转换为一个 SpriteEntry。

原始 OAM 布局

sprite 0 -> bytes 0, 1, 2, 3
sprite 1 -> bytes 4, 5, 6, 7
...
sprite 63 -> bytes 252, 253, 254, 255

建议的实现示例

def decode_sprite_entry(oam: bytes | bytearray, sprite_index: int) -> SpriteEntry:
    if len(oam) < OAM_SIZE:
        raise ValueError("OAM must contain 256 bytes")

    if not 0 <= sprite_index < OAM_SPRITE_COUNT:
        raise ValueError("sprite_index must be in range 0..63")

    base = sprite_index * BYTES_PER_SPRITE

    return SpriteEntry(
        y=oam[base],
        tile_index=oam[base + 1],
        attributes=oam[base + 2],
        x=oam[base + 3],
    )

重要的 NES 细节

原始 Y 字节在真实硬件上具有特殊的渲染语义。精灵显示在存储的 Y 值下方一条扫描线处。不要在此解码器中调整它。此函数仅返回原始 OAM 数据。

超出本步骤范围

  • 精灵属性位解码
  • 精灵调色板
  • 渲染像素
  • 精灵 0 命中
  • 精灵溢出
  • pygame

运行本课

uv run pytest tests/chapter_09_sprite_rendering/test_300_decode_sprite_entry.py -v