323. Console планирует sprite zero hit на каждый кадр
Автоматически планировать sprite 0 hit при продвижении Console на кадр вперёд.
Урок 323 из 356 · tests/chapter_11_sprite_zero_hit/test_323_console_schedules_sprite_zero_hit_per_frame.py
Файл для обновления
emulator/console.pyЗачем нужен этот шаг
Предыдущие шаги предоставляют все необходимые механизмы
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 positionЭтот шаг соединяет их с циклом кадра.
Архитектурное решение
Мы намеренно помещаем подготовку sprite zero hit внутрь Console.step_until_next_frame(). Вызывающий код, такой как main.py, должен просить Console продвинуться на один полный эмулируемый кадр, не зная, какие внутренние события тайминга PPU нужно подготовить заранее.
Это позволяет main.py оставаться сосредоточенным на обязанностях фронтенда:
input
display
FPS reporting
frame pacingConsole владеет координацией эмулятора на уровне кадра.
Предлагаемое изменение реализации
# --- 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:
...Почему до цикла пошагового выполнения? CPU может опрашивать PPUSTATUS во время эмуляции кадра. Будущее срабатывание должно быть запланировано до того, как выполнение CPU/PPU достигнет перекрывающегося пикселя.
Контрольная точка ручной проверки совместимости
После этого шага студенты могут временно изменить локальный путь к ручному ROM в main.py на собственную легальную копию:
Предлагаемое изменение реализации в main.py:
ROM_PATH = Path("Super Mario Bros.nes")Затем запустить с помощью PyPy
Linux/macOS
sh launcher.shКомандная строка Windows
launcher.cmdОжидаемое улучшение при ручной проверке
Super Mario Bros. использует sprite 0 hit как сигнал тайминга PPU. Теперь, когда срабатывание обнаруживается, планируется и предоставляется через PPUSTATUS, титульный экран/меню должны продвигаться дальше, Марио должен появиться, а ввод с контроллера должен стать рабочим.
Известное оставшееся ограничение
Когда Марио движется по горизонтали, сцена может по-прежнему выглядеть некорректно, поскольку текущий рендерер фона ещё не применяет состояние прокрутки PPU для выбора и смещения видимой области nametable. Sprite 0 hit включает путь тайминга игры; он не реализует горизонтальную прокрутку фона.
Правило легальности/тестирования
Super Mario Bros.nes — это только ручной эксперимент совместимости, предоставляемый пользователем. Не коммитьте ROM и не требуйте его в автоматических тестах. Эти тесты используют поддельные объекты CPU/PPU и проверяют только поведение координации.
Вне рамок
- горизонтальная/вертикальная прокрутка
- тонкая прокрутка по X
- композиция соседних nametable
- точное поведение OAM Y+1
- правила левого края PPUMASK
- исключение sprite 0 hit при x=255
- фикстуры коммерческих ROM
Запустить этот урок
uv run pytest tests/chapter_11_sprite_zero_hit/test_323_console_schedules_sprite_zero_hit_per_frame.py -v