312. 精灵优先级使用背景不透明掩码

使用背景不透明度掩码来应用精灵优先级第 5 位。

312 / 356 · tests/chapter_09_sprite_rendering/test_312_sprite_priority_uses_background_opaque_mask.py

需要更新的文件

emulator/rendering/sprite_renderer.py

为什么需要这一步

步骤 310 构建了逐像素的背景不透明度掩码。步骤 311 将该掩码传递到了精灵渲染流水线中。这一步最终在单精灵渲染器中使用该掩码。

规则

If a sprite pixel is non-transparent,
and the sprite has priority bit 5 set,
and the background mask says that screen pixel is opaque,
then keep the background pixel and skip drawing the sprite pixel.

重要的顺序要求

1. sprite CHR color index 0 -> skip
2. offscreen pixel -> skip
3. behind-background sprite over opaque background -> skip
4. otherwise draw sprite pixel

示例实现片段

def render_sprite_8x8_to_framebuffer (...) -> ...

...
... 

screen_x = sprite.x + tile_x
screen_y = sprite.y + tile_y

if not (0 <= screen_x < framebuffer.width):
    continue
if not (0 <= screen_y < framebuffer.height):
    continue

# --- ADD THIS NEW BLOCK ---
if (
    background_opaque_mask is not None
    and attributes.is_behind_background
    and background_opaque_mask[screen_y * framebuffer.width + screen_x]
):
    continue
# --- END NEW BLOCK ---

framebuffer.set_pixel(...)

为什么要在裁剪之后?掩码索引使用的是屏幕坐标。如果在检查像素是否在屏幕内之前就对掩码进行索引,屏幕外的精灵可能会读取到错误的掩码项,或引发 IndexError。

本步骤范围之外

  • 在 Console.render_framebuffer() 内部构建掩码
  • 根据 PPUCTRL 第 4 位选择背景图案表
  • 精灵 0 命中
  • 精灵溢出
  • pygame

运行本课

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