286. Ручной главный цикл pygame
Добавить ручной главный цикл pygame для запуска проверки framebuffer.
Урок 286 из 356 · tests/chapter_05_rendering_pipeline/test_286_manual_pygame_main_loop.py
Файлы для обновления/создания
tools/show_framebuffer.pyЗачем нужен этот шаг
На предыдущем шаге были добавлены помощники, способные отрисовать Framebuffer на pygame Surface. На этом шаге добавляется ручной цикл окна, чтобы разработчик мог визуально убедиться, что чистые данные Framebuffer можно отобразить.
Важно
Это ручной инструмент для проверки работоспособности, а не автоматизированный тест рендеринга. Автоматизированные тесты не должны открывать настоящее окно pygame.
Запускайте инструмент как модуль Python
uv run python -m tools.show_framebufferФлаг -m в Python ожидает имя модуля, а не путь к файлу. Имя модуля использует точки:
tools.show_framebufferа не путь к файлу:
tools/show_framebuffer.pyСовременный Python поддерживает такую структуру проекта как пакет пространства имён, поэтому в этом уроке файл __init__.py не требуется.
Ручные команды
Correct:
uv run python -m tools.show_framebuffer
Incorrect:
uv run python -m tools/show_framebuffer.py
uv run python -m tools.show_framebuffer.pyЧто такое главный цикл pygame?
Главный цикл pygame поддерживает окно активным, многократно выполняя
1. reading events
2. drawing to the window surface
3. presenting the drawn imageМинимальная структура
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
draw_framebuffer(window, framebuffer, SCALE)
pygame.display.flip()Что делает pygame.display.flip()? Она выводит текущее содержимое поверхности окна на экран. Проще говоря:
draw pixels -> flip -> user sees pixelsОжидаемый визуальный результат при ручной проверке
Framebuffer в виде шахматной доски должен показывать чёрно-белый или тёмно-светлый узор, например:
+----------------+
| ██ ██ ██ ██ |
| ██ ██ ██ ██ |
| ██ ██ ██ |
| ██ ██ ██ |
| ██ ██ ██ ██ |
| ██ ██ ██ ██ |
+----------------+Точный размер блоков зависит от размера framebuffer и SCALE, но важна следующая визуальная проверка:
alternating light and dark squares are visible
closing the window exits cleanlyПример предлагаемой реализации
SCALE = 3
def main() -> None:
framebuffer = make_checkerboard_framebuffer()
pygame.init()
try:
window = pygame.display.set_mode(
(framebuffer.width * SCALE, framebuffer.height * SCALE)
)
pygame.display.set_caption("Framebuffer Smoke Test")
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
draw_framebuffer(window, framebuffer, SCALE)
pygame.display.flip()
finally:
pygame.quit()
if __name__ == "__main__":
main()Архитектурное правило
pygame остаётся вне ядра эмулятора. Этот файл может импортировать pygame, поскольку находится в tools/. Не импортируйте pygame из emulator/rendering, emulator/ppu или emulator/console.
Вне рамок этого шага
- тестирование настоящего окна pygame в pytest
- загрузка ROM
- рендеринг живого вывода Console
- ввод с контроллера
- спрайты
Запустить этот урок
uv run pytest tests/chapter_05_rendering_pipeline/test_286_manual_pygame_main_loop.py -v