323. Console schedules sprite zero hit per frame
Schedule sprite 0 hit automatically when Console advances a frame.
Lesson 323 of 356 · tests/chapter_11_sprite_zero_hit/test_323_console_schedules_sprite_zero_hit_per_frame.py
File to update
emulator/console.pyWhy this step exists
The previous steps provide all required mechanisms
ppu_sprite_zero_hit_position(ppu)
-> extracts current PPU state and finds the overlap position
ppu.set_sprite_zero_hit_position(position)
-> stores the future timing event
ppu.step(...)
-> sets PPUSTATUS bit 6 when timing reaches that positionThis step connects them to the frame loop.
Architecture decision
We intentionally put sprite-zero-hit preparation inside Console.step_until_next_frame(). A caller such as main.py should ask Console to advance one complete emulated frame without knowing which internal PPU timing events must be prepared first.
This keeps main.py focused on frontend responsibilities:
input
display
FPS reporting
frame pacingConsole owns frame-level emulator coordination.
Suggested implementation change
# --- NEW LINE ---
from emulator.rendering.sprite_zero_hit import ppu_sprite_zero_hit_position
# --- END NEW LINE ---
def step_until_next_frame(
self,
max_cpu_instructions: int | None = None,
) -> int:
# --- NEW BLOCK ---
position = ppu_sprite_zero_hit_position(self.ppu)
self.ppu.set_sprite_zero_hit_position(position)
# --- END NEW BLOCK ---
start_frame = self.ppu.frame
executed = 0
while self.ppu.frame == start_frame:
...Why before the stepping loop? The CPU may poll PPUSTATUS while the frame is being emulated. The future hit must be scheduled before CPU/PPU execution reaches the overlapping pixel.
Manual compatibility checkpoint
After this step, students may temporarily change the local manual ROM path in main.py to their own legal copy:
Suggested implementation change in main.py:
ROM_PATH = Path("Super Mario Bros.nes")Then run with PyPy
Linux/macOS
sh launcher.shWindows Command Prompt
launcher.cmdExpected manual improvement
Super Mario Bros. uses sprite 0 hit as a PPU timing signal. With the hit now detected, scheduled, and exposed through PPUSTATUS, the title/menu should progress further, Mario should appear, and controller input should become usable.
Known remaining limitation
When Mario advances horizontally, the scene may still look incorrect because the current background renderer does not yet apply the PPU scrolling state to select and offset the visible nametable region. Sprite 0 hit enables the game's timing path; it does not implement horizontal background scrolling.
Legal/testing rule
Super Mario Bros.nes is a manual, user-provided compatibility experiment only. Do not commit the ROM and do not require it from automated tests. These tests use fake CPU/PPU objects and inspect coordination behavior only.
Out of scope
- horizontal/vertical scrolling
- fine X scrolling
- adjacent nametable composition
- exact OAM Y+1 behavior
- PPUMASK left-edge rules
- x=255 sprite 0 hit exception
- commercial ROM fixtures
Run this lesson
uv run pytest tests/chapter_11_sprite_zero_hit/test_323_console_schedules_sprite_zero_hit_per_frame.py -v