322. Ppu sprite zero hit position
Extract the sprite 0 overlap position from current PPU state.
Lesson 322 of 356 · tests/chapter_11_sprite_zero_hit/test_322_ppu_sprite_zero_hit_position.py
File to update
emulator/rendering/sprite_zero_hit.pyWhy this step exists
The existing pure helper requires explicit rendering data
find_sprite_zero_hit_position(
sprite_zero,
pattern_table,
background_opaque_mask,
)That API is useful for focused tests, but a future Console step starts with a PPU. This step adds a small adapter that extracts the required data from current PPU state and delegates to the existing pure helper.
Keeping both functions in sprite_zero_hit.py is clear at the current project size:
find_sprite_zero_hit_position(...)
explicit data -> overlap position
ppu_sprite_zero_hit_position(ppu)
PPU state -> explicit data -> overlap positionThe second function is an adapter, not another overlap algorithm.
Required extraction
- decode OAM entry 0 only
- build the background opacity mask through ppu_background_to_opaque_mask(ppu)
- select the sprite pattern table using PPUCTRL bit 3
- read PATTERN_TABLE_SIZE bytes through PpuBus
- delegate to find_sprite_zero_hit_position(...)
Suggested implementation example
from emulator.ppu.chr_decoder import PATTERN_TABLE_SIZE, decode_chr_tile
from emulator.ppu.ppu import CTRL_SPRITE_PATTERN_TABLE, PPU
from emulator.rendering.ppu_background_renderer import (
PATTERN_TABLE_0_ADDR,
PATTERN_TABLE_1_ADDR,
ppu_background_to_opaque_mask,
)
from emulator.rendering.sprite_renderer import (
SpriteEntry,
decode_sprite_attributes,
decode_sprite_entry,
)
...
def ppu_sprite_zero_hit_position(
ppu: PPU,
) -> SpriteZeroHitPosition | None:
sprite_zero = decode_sprite_entry(
oam=ppu.oam,
sprite_index=0,
)
background_opaque_mask = ppu_background_to_opaque_mask(ppu)
sprite_pattern_table_base = (
PATTERN_TABLE_1_ADDR
if ppu.ctrl & CTRL_SPRITE_PATTERN_TABLE
else PATTERN_TABLE_0_ADDR
)
sprite_pattern_table = bytes(
ppu.ppu_bus.read(sprite_pattern_table_base + offset)
for offset in range(PATTERN_TABLE_SIZE)
)
return find_sprite_zero_hit_position(
sprite_zero=sprite_zero,
pattern_table=sprite_pattern_table,
background_opaque_mask=background_opaque_mask,
)Important distinction
Background opacity uses the background pattern-table selection path, which is based on PPUCTRL bit 4. Sprite 0 CHR data uses PPUCTRL bit 3. The two selections may point to different pattern tables.
Important boundary
This function only returns a position. It does not set PPUSTATUS and does not call PPU.set_sprite_zero_hit_position(). Console wiring remains a later step.
Out of scope
- Console wiring
- automatic scheduling
- PPUMASK rendering-enable rules
- left-edge clipping rules
- x=255 hardware exception
- OAM Y+1 correction
- Super Mario Bros. validation
Run this lesson
uv run pytest tests/chapter_11_sprite_zero_hit/test_322_ppu_sprite_zero_hit_position.py -v