286. 手动 pygame 主循环
为帧缓冲冒烟运行器添加手动 pygame 主循环。
第 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_framebufferPython 的 -m 参数期望的是模块名,而不是文件路径。模块名使用点号:
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()?它把窗口 surface 的当前内容呈现到显示器上。简单来说:
draw pixels -> flip -> user sees pixels预期的手动视觉结果
棋盘格帧缓冲应该显示出类似这样的黑/白或深色/白色图案:
+----------------+
| ██ ██ ██ ██ |
| ██ ██ ██ ██ |
| ██ ██ ██ |
| ██ ██ ██ |
| ██ ██ ██ ██ |
| ██ ██ ██ ██ |
+----------------+确切的方块大小取决于帧缓冲尺寸和 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/ 目录下。不要在 emulator/rendering、emulator/ppu 或 emulator/console 中导入 pygame。
范围之外
- 在 pytest 中测试真实的 pygame 窗口
- 加载 ROM
- 渲染实时的 Console 输出
- 手柄输入
- 精灵
运行本课
uv run pytest tests/chapter_05_rendering_pipeline/test_286_manual_pygame_main_loop.py -v