286. Bucle principal manual de pygame

Añadir un bucle principal manual de pygame para el ejecutor de comprobación rápida del framebuffer.

Lección 286 de 356 · tests/chapter_05_rendering_pipeline/test_286_manual_pygame_main_loop.py

Archivos a actualizar/crear

tools/show_framebuffer.py

Por qué existe este paso

El paso anterior añadió ayudantes que pueden dibujar un Framebuffer sobre una Surface de pygame. Este paso añade el bucle de ventana manual para que un desarrollador pueda confirmar visualmente que los datos de Framebuffer puros se pueden mostrar.

Importante

Esto es un ejecutor manual de comprobación rápida, no un test de renderizado automatizado. Los tests automatizados no deben abrir una ventana real de pygame.

Ejecuta la herramienta como un módulo de Python

uv run python -m tools.show_framebuffer

El flag -m de Python espera un nombre de módulo, no una ruta de archivo. El nombre del módulo usa puntos:

tools.show_framebuffer

no como una ruta de archivo:

tools/show_framebuffer.py

El Python moderno admite este diseño de proyecto como paquete de espacio de nombres (namespace package), así que esta lección no requiere un archivo __init__.py.

Comandos manuales

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

¿Qué es el bucle principal de pygame?

Un bucle principal de pygame mantiene una ventana viva repitiendo

1. reading events
2. drawing to the window surface
3. presenting the drawn image

Forma mínima

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()

¿Qué es pygame.display.flip()? Presenta el contenido actual de la superficie de la ventana en la pantalla. En términos simples:

draw pixels -> flip -> user sees pixels

Resultado visual manual esperado

El framebuffer en forma de tablero de ajedrez debería mostrar un patrón blanco/negro u oscuro/blanco como:

+----------------+
| ██  ██  ██  ██ |
| ██  ██  ██  ██ |
|   ██  ██  ██   |
|   ██  ██  ██   |
| ██  ██  ██  ██ |
| ██  ██  ██  ██ |
+----------------+

El tamaño exacto de los bloques depende del tamaño del framebuffer y de SCALE, pero la comprobación visual importante es:

alternating light and dark squares are visible
closing the window exits cleanly

Ejemplo de implementación sugerida

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()

Regla de arquitectura

pygame permanece fuera del núcleo del emulador. Este archivo puede importar pygame porque vive bajo tools/. No importes pygame desde emulator/rendering, emulator/ppu ni emulator/console.

Fuera de alcance

  • probar la ventana real de pygame en pytest
  • cargar ROMs
  • renderizar la salida en vivo de Console
  • entrada del mando
  • sprites

Ejecutar esta lección

uv run pytest tests/chapter_05_rendering_pipeline/test_286_manual_pygame_main_loop.py -v