如何优化Pygame点击波浪扩散效果代码以提升运行效率?
优化Pygame波浪式方块扩散性能的方案
你的核心问题在于维护了所有已变红的方块列表,每次遍历整个列表检查邻接——随着扩散范围扩大,列表呈指数级增长,导致每次迭代的计算量和绘制量飙升。下面给出两种无需全局逐像素检查的高效实现方案,完全满足渐进式扩散、任意点击触发的需求:
方案一:分层BFS(广度优先搜索)
BFS天然适配波浪式扩散的特性,我们只需要维护当前扩散波前的方块层,而非所有已变红的方块。每次仅处理当前层的方块,将其邻接未变红的方块加入下一层,循环迭代即可实现平滑扩散。
代码示例
import pygame import sys from collections import deque pygame.init() SCREEN_SIZE = (800, 600) CELL_SIZE = 10 # 单个方块的像素尺寸 GRID_WIDTH = SCREEN_SIZE[0] // CELL_SIZE GRID_HEIGHT = SCREEN_SIZE[1] // CELL_SIZE screen = pygame.display.set_mode(SCREEN_SIZE) clock = pygame.time.Clock() # 记录已访问的方块,避免重复处理 visited = [[False]*GRID_HEIGHT for _ in range(GRID_WIDTH)] # 存储当前扩散层的网格坐标 current_layer = deque() def start_diffusion(screen_x, screen_y): # 转换屏幕坐标为网格坐标 grid_x = screen_x // CELL_SIZE grid_y = screen_y // CELL_SIZE if 0 <= grid_x < GRID_WIDTH and 0 <= grid_y < GRID_HEIGHT and not visited[grid_x][grid_y]: visited[grid_x][grid_y] = True current_layer.clear() current_layer.append((grid_x, grid_y)) running = True while running: screen.fill((255,255,255)) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.MOUSEBUTTONDOWN: start_diffusion(*event.pos) # 处理当前扩散层,生成下一层 next_layer = deque() for gx, gy in current_layer: # 绘制当前方块 pygame.draw.rect(screen, (255,0,0), (gx*CELL_SIZE, gy*CELL_SIZE, CELL_SIZE, CELL_SIZE)) # 检查四个方向的邻接方块 for dx, dy in [(-1,0), (1,0), (0,-1), (0,1)]: nx, ny = gx + dx, gy + dy if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT and not visited[nx][ny]: visited[nx][ny] = True next_layer.append((nx, ny)) # 更新为下一轮的扩散层 current_layer = next_layer pygame.display.flip() clock.tick(30) pygame.quit() sys.exit()
优势
- 每次仅处理当前波前的方块,计算量与扩散周长成正比,而非总面积
- 内存占用极低,仅需存储当前层和下一层的坐标
- 天然支持任意点击位置触发扩散,扩散逻辑平滑自然
方案二:距离场直接绘制环形波
如果追求极致性能,可以直接通过距离计算生成当前扩散半径对应的方块,无需维护任何已访问列表或队列。核心思路是:维护扩散中心和当前半径,每次仅绘制与中心距离等于当前半径的方块。
代码示例
import pygame import sys pygame.init() SCREEN_SIZE = (800, 600) CELL_SIZE = 10 GRID_WIDTH = SCREEN_SIZE[0] // CELL_SIZE GRID_HEIGHT = SCREEN_SIZE[1] // CELL_SIZE screen = pygame.display.set_mode(SCREEN_SIZE) clock = pygame.time.Clock() diffusion_center = None current_radius = 0 def start_diffusion(screen_x, screen_y): global diffusion_center, current_radius diffusion_center = (screen_x // CELL_SIZE, screen_y // CELL_SIZE) current_radius = 0 running = True while running: screen.fill((255,255,255)) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.MOUSEBUTTONDOWN: start_diffusion(*event.pos) if diffusion_center is not None: cx, cy = diffusion_center # 遍历当前半径覆盖的网格范围,仅绘制距离等于当前半径的方块 for gx in range(max(0, cx - current_radius), min(GRID_WIDTH, cx + current_radius + 1)): for gy in range(max(0, cy - current_radius), min(GRID_HEIGHT, cy + current_radius + 1)): # 用棋盘距离(最大坐标差)模拟方块风格的波浪 distance = max(abs(gx - cx), abs(gy - cy)) if distance == current_radius: pygame.draw.rect(screen, (255,0,0), (gx*CELL_SIZE, gy*CELL_SIZE, CELL_SIZE, CELL_SIZE)) # 递增半径,直到超出屏幕范围 if current_radius < max(GRID_WIDTH, GRID_HEIGHT): current_radius += 1 pygame.display.flip() clock.tick(30) pygame.quit() sys.exit()
优势
- 完全无需邻接检查或状态维护,性能最优
- 代码逻辑简洁,易于调整扩散速度、波浪形状(比如改用欧氏距离实现圆形波浪)
- 支持多点击触发多波扩散(只需维护多个中心和半径即可)
内容的提问来源于stack exchange,提问作者ImBadAtMath
相关产品推荐
相关产品推荐

