基于Pyglet的沙子模拟渲染缓慢问题求助
优化Pyglet沙子模拟器的渲染与运行速度
你的代码性能问题核心在于每帧重复创建图形对象和状态更新逻辑的低效,以下是针对性的优化方案:
1. 预创建所有网格矩形,避免重复实例化
原代码在on_draw中每次循环都新建shapes.Rectangle对象,这会产生大量不必要的内存分配与销毁,是性能瓶颈的关键。我们可以在初始化阶段就创建好所有格子的矩形,之后只需要根据网格状态更新颜色即可。
2. 优化沙子下落的状态更新逻辑
- 避免每帧新建二维数组:复用现有数组或复制当前状态后修改,减少内存开销
- 调整遍历顺序:从底部到顶部遍历列,确保沙子下落逻辑正确且不会重复处理同一粒沙子
- 简化数组初始化:移除冗余的二次赋值操作
修改后的完整代码
import math import pyglet from pyglet import shapes from pyglet.window import mouse SCREEN_WIDTH = 400 SCREEN_HEIGHT = 400 SAND_SIZE = 10 def make2DArray(rows, cols): # 简化二维数组初始化逻辑 return [[0 for _ in range(cols)] for _ in range(rows)] window = pyglet.window.Window(SCREEN_WIDTH, SCREEN_HEIGHT) rows = int(SCREEN_WIDTH / SAND_SIZE) cols = int(SCREEN_HEIGHT / SAND_SIZE) grid = make2DArray(rows, cols) grid[30][20] = 1 # 预创建所有网格矩形并存储 grid_shapes = [] for row in range(rows): row_shapes = [] for col in range(cols): x = row * SAND_SIZE y = col * SAND_SIZE rect = shapes.Rectangle(x, y, SAND_SIZE, SAND_SIZE, color=(0, 0, 0)) row_shapes.append(rect) grid_shapes.append(row_shapes) @window.event def on_mouse_drag(x, y, dx, dy, buttons, modifiers): row = math.floor(x / SAND_SIZE) col = math.floor(y / SAND_SIZE) # 防止坐标越界 if 0 <= row < rows and 0 <= col < cols: grid[row][col] = 1 grid_shapes[row][col].color = (255, 255, 255) @window.event def on_draw(): window.clear() # 批量绘制所有预创建的矩形 for row in grid_shapes: for rect in row: rect.draw() # 从下往上更新沙子状态,避免重复移动 next_grid = [row.copy() for row in grid] for row in range(rows): # 从顶部到底部遍历列(对应屏幕从下到上) for col in range(cols-1, -1, -1): if grid[row][col] == 1: # 检查下方是否有空位 if col > 0 and grid[row][col-1] == 0: next_grid[row][col] = 0 next_grid[row][col-1] = 1 # 同步更新图形颜色 grid_shapes[row][col].color = (0, 0, 0) grid_shapes[row][col-1].color = (255, 255, 255) grid = next_grid pyglet.app.run()
额外优化方向
- 补充左右下落逻辑(参考原p5.js实现,让沙子可以向左下/右下移动),提升模拟真实度
- 使用
pyglet.graphics.Batch批量管理所有矩形,只需一次batch.draw()调用即可完成绘制,进一步提升渲染效率 - 针对超大网格,可只绘制状态变化的格子,减少无效绘制调用
内容的提问来源于stack exchange,提问作者Mauro Ds
相关产品推荐
相关产品推荐

