353. Sprite zero hit usa la máscara de viewport

Usar la opacidad de fondo consciente del viewport para la detección de solapamiento de sprite-zero-hit.

Lección 353 de 356 · tests/chapter_13_scrolling/test_353_sprite_zero_hit_uses_viewport_mask.py

Archivo a actualizar

emulator/rendering/sprite_zero_hit.py

Referencias

https://www.nesdev.org/wiki/PPU_rendering
https://www.nesdev.org/wiki/PPU_scrolling

Por qué existe este paso

Sprite zero hit es una señal de estado de la PPU que se produce cuando un píxel opaco de la entrada de sprite 0 de OAM se solapa con un píxel de fondo opaco. Los juegos pueden sondear esta señal para temporizar un cambio de registro a mitad de fotograma, como separar un área de estado fija del juego con desplazamiento.

El helper de solapamiento indexa la opacidad de fondo usando coordenadas de pantalla

mask_index = screen_y * 256 + screen_x

Por tanto, esa máscara debe describir el fondo realmente visible en esas mismas coordenadas. Tras el desplazamiento temporizado, la X de pantalla puede corresponder a una columna coarse-X distinta o a una nametable lógica distinta en cada fila. La antigua máscara fija en $2000 puede inspeccionar un píxel de fondo distinto aunque el sprite 0 permanezca en la misma posición de pantalla.

Ejemplo

sprite 0 screen X:       100
scanline viewport X:      40
visible background X:    140

fixed mask inspects X:   100
viewport mask inspects X: 140

Si la X de origen 140 es opaca y la X de origen 100 es transparente, la máscara fija pasa por alto el solapamiento. El adaptador consciente del viewport selecciona la composición temporizada para un fotograma completo y conserva la reserva de instantánea ya probada cuando los datos temporizados no están disponibles.

¿Por qué usar un alias de importación? Las pruebas históricas de sprite-zero-hit hacen monkeypatch del nombre local del módulo ppu_background_to_opaque_mask. Cambiar cada llamada a un nuevo nombre local rompería ese punto de prueba estable. Importar el adaptador consciente del viewport bajo el nombre histórico cambia el comportamiento de producción manteniendo las pruebas antiguas sin cambios:

new viewport-aware function as old module-local name

Invariantes importantes

  • sprite-zero-hit consume el adaptador de opacidad consciente del viewport
  • el nombre histórico de la dependencia local sigue siendo monkeypatchable
  • la máscara seleccionada se pasa sin cambios al helper de solapamiento puro
  • la selección de la tabla de patrones CHR del sprite permanece independiente del enmascarado de fondo
  • el código de renderizado no establece PPUSTATUS directamente
  • Console y la temporización de la PPU siguen programando y estableciendo el hit

Concepto erróneo habitual

Sprite zero hit no es detección de colisiones de juego y no significa que Mario haya golpeado a un enemigo o un bloque. Es un solapamiento de renderizado que involucra únicamente la entrada de sprite 0 y un píxel de patrón de fondo opaco, usado habitualmente por el software como señal de temporización.

Estrategia de pruebas

Una prueba comprueba la identidad de la dependencia de producción para que el antiguo productor fijo no pueda volver silenciosamente. Otra sigue un fotograma temporizado completo a través del adaptador de viewport real reemplazando solo su costoso compositor de filas, y luego verifica que la máscara resultante llega sin cambios al límite existente del helper de solapamiento puro.

Fuera de alcance

  • cambiar la búsqueda de solapamiento pura
  • cambiar la selección de la tabla de patrones del sprite
  • cambiar la programación de fotogramas de Console
  • comportamiento exacto de hardware del borde izquierdo, X=255 y OAM Y+1
  • desplazamiento vertical completo de la fila de origen

Implementación de ejemplo completa

# emulator/rendering/sprite_zero_hit.py

# --- UPDATED BLOCK: VIEWPORT MASK WITH HISTORICAL LOCAL NAME ---
from emulator.rendering.ppu_background_renderer import (
    PATTERN_TABLE_0_ADDR,
    PATTERN_TABLE_1_ADDR,
    ppu_background_viewport_to_opaque_mask as ppu_background_to_opaque_mask,
)

...

Ejecutar esta lección

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