如何在Pygame中实现视野渐缩关闭?性能优化求助
优化Pygame径向缩小视野的性能问题
嘿,你猜的完全没错——随着visionradius增大,你绘制的圆环宽度越来越夸张,Pygame需要处理的像素量呈爆炸式增长,这就是卡顿的核心原因。另外你的代码里还有个隐藏的性能坑:surface每次循环都没清空,导致新画的圆环和旧的叠加在一起,进一步拖慢了运行速度。
下面给你两个高效的解决方案,从根本上解决这个问题:
方案一:反向绘制可见区域(首推)
与其费劲画越来越宽的遮罩圆环,不如换个思路:先画全屏的半透明遮罩,再在中心挖一个实心的“可见圆”(用完全透明的颜色填充)。这种方式每次只需要做两个简单的绘制操作——全屏矩形填充和实心圆绘制,不管视野多大,性能都稳得一批。
修改后的核心代码如下:
import pygame as pg pg.init() pg.display.init() screensize = (width, height) = (600, 600) center = (int(width/2), int(height/2)) screen = pg.display.set_mode(screensize) # 创建带透明通道的全屏遮罩Surface mask_surface = pg.Surface(screensize, pg.SRCALPHA) # 遮罩用你原来的半透明绿色 mask_color = (10, 255, 10, 230) # 初始可见半径对应你原来的600 - 初始visionradius(20) vision_radius = 580 run = True def CONDITION(): # 替换成你的实际条件判断逻辑 return True # 用Clock控制帧率更稳定 clock = pg.Clock() while run: clock.tick(60) # 锁定60帧,比delay更流畅 for event in pg.event.get(): if event.type == pg.QUIT: run = False # 满足条件时缩小视野(可见半径减小) if CONDITION() and vision_radius > 0: vision_radius -= 1 # 先画游戏背景 screen.fill((255, 255, 255)) # 这里可以添加角色、游戏元素的绘制逻辑 # 更新遮罩:先铺满半透明遮罩 mask_surface.fill(mask_color) # 在遮罩上挖空可见区域(完全透明的圆) pg.draw.circle(mask_surface, (0, 0, 0, 0), center, vision_radius) # 把遮罩贴到屏幕上 screen.blit(mask_surface, (0, 0)) # 视野完全关闭时结束游戏 if vision_radius <= 0: run = False pg.display.update() pg.quit()
为啥这个方案更快?
- 全屏矩形填充是Pygame里最快的绘制操作之一,很多时候是硬件加速的。
- 实心圆的绘制成本远低于宽圆环,而且随着视野缩小,圆越来越小,绘制速度还会越来越快。
- 每次循环都重新填充遮罩,彻底避免了旧像素叠加的性能损耗。
方案二:预生成遮罩帧(适合固定速率的视野变化)
如果你的视野缩小速率是固定的,可以提前把所有需要的遮罩都生成好,运行时直接切换就行,完全不用实时绘制,性能拉满。
示例代码片段:
# 预生成所有遮罩帧 mask_frames = [] max_radius = 600 for radius in range(max_radius, -1, -1): frame = pg.Surface(screensize, pg.SRCALPHA) frame.fill(mask_color) pg.draw.circle(frame, (0,0,0,0), center, radius) mask_frames.append(frame) # 运行时直接用预生成的帧 current_frame = 0 while run: clock.tick(60) for event in pg.event.get(): if event.type == pg.QUIT: run = False if CONDITION() and current_frame < len(mask_frames)-1: current_frame += 1 # 绘制背景和游戏元素 screen.fill((255,255,255)) # 贴预生成的遮罩 screen.blit(mask_frames[current_frame], (0,0)) if current_frame >= len(mask_frames)-1: run = False pg.display.update()
注意点
- 预生成会占用一些内存,600x600的Surface每个约1.44MB,601帧总共大概865MB。如果觉得内存压力大,可以每隔几个半径生成一个帧,用平滑过渡的方式弥补视觉差异。
额外的小优化
- 把
pg.time.delay(20)换成pg.Clock().tick(60),这样游戏帧率更稳定,不会因为绘制耗时导致速度忽快忽慢。 - 确保你的
CONDITION()函数逻辑尽可能简单,别在循环里搞复杂计算,不然也会拖慢速度。
内容的提问来源于stack exchange,提问作者José Chamorro
相关产品推荐
相关产品推荐

