Pygame精灵无法正常显示:仅点击窗口关闭按钮时闪显求助
解决Pygame中Sprite仅在退出时闪显的问题
看起来你遇到的问题根源在于主循环嵌套导致渲染流程混乱,加上多处分散调用pygame.display.update(),使得角色Sprite的绘制没有被正确刷新到屏幕上。咱们一步步拆解问题并修复:
问题分析
- 嵌套循环阻塞渲染:你的
main()函数里有一个while True循环,每次调用movePlayer(),而movePlayer()自身又包含一个while run循环。这导致地图绘制只在movePlayer()启动前执行一次,而角色的绘制在子循环中,但由于渲染时机不统一,角色被地图覆盖无法正常显示——只有当你点击关闭按钮退出子循环时,角色的最后一次绘制才会短暂闪显。 - 多处更新显示导致混乱:
redrawGameWindow()和multilineRender()里都调用了pygame.display.update(),这会让显示刷新不连贯,部分绘制操作可能被覆盖或延迟。 - 退出后无效绘制:点击关闭按钮退出
movePlayer()的循环后,main()的while True会再次调用multilineRender(),但此时pygame.display.quit()已经执行,导致pygame.error: display Surface quit的报错。
修复方案
我们需要重构主循环,统一渲染流程,确保所有绘制和更新都在一个循环中有序执行:
1. 修改Player类的渲染方法
移除类中单独的pygame.display.update(),把显示更新统一交给主循环:
class player(): def __init__(self, x, y, width, height, walkCount): self.x = x self.y = y self.width = width self.height = height self.vel = 5 self.up = False self.down = False self.left = False self.right = False self.walkCount = walkCount # 移除原代码中重复定义的self.up/self.down def redrawGameWindow(self, window): dest = (self.x, self.y) if self.walkCount + 1 >= 30: self.walkCount = 0 if self.left: window.blit(protagL[self.walkCount//3], dest) self.walkCount += 1 elif self.right: window.blit(protagR[self.walkCount//3], dest) self.walkCount += 1 elif self.up: window.blit(protagU[self.walkCount//3], dest) self.walkCount += 1 elif self.down: window.blit(protagD[self.walkCount//3], dest) self.walkCount += 1 else: window.blit(protagL[0], dest) # 默认显示左方向的第一张图,更稳定 # 移除这里的pygame.display.update()
2. 修改地图渲染函数
同样移除函数内的pygame.display.update():
def multilineRender(screen, text, x, y, the_font, colour=(0, 0, 0), justification="left"): justification = justification[0].upper() max_width = 0 text_bitmaps = [] # 转换文本为位图并计算最大宽度 for char in text: text_bitmap = the_font.render(char, True, colour) text_width = text_bitmap.get_width() text_bitmaps.append((text_width, text_bitmap)) if max_width < text_width: max_width = text_width # 绘制文本 for (width, bitmap) in text_bitmaps: xPos = x width_diff = max_width - width if justification == 'R': xPos = x + width_diff elif justification == 'C': xPos = x + (width_diff // 2) screen.blit(bitmap, (xPos, y)) y += bitmap.get_height() # 移除这里的pygame.display.update()
3. 重构主函数,合并循环
把movePlayer()的逻辑整合到main()的主循环中,统一处理输入、渲染和显示更新:
def main(): # 读取地图文件 inFile = open("map(TEST).txt", "r") text = inFile.read().splitlines() inFile.close() # 初始化Pygame(确保你已经定义了window变量,比如window = pygame.display.set_mode((550, 500))) pygame.init() window.fill((0, 0, 0)) myfont = pygame.font.SysFont("Calibri", 35) board = player(30, 45, 64, 64, 0) clock = pygame.time.Clock() run = True while run: clock.tick(15) # 处理事件 for event in pygame.event.get(): if event.type == pygame.QUIT: run = False # 处理键盘输入 arrowKeys = pygame.key.get_pressed() if arrowKeys[pygame.K_LEFT] and board.x > 25 + board.vel: board.x -= board.vel board.left = True board.right = False board.up = False board.down = False elif arrowKeys[pygame.K_RIGHT] and board.x < 510 - board.width - board.vel: board.x += board.vel board.right = True board.left = False board.up = False board.down = False elif arrowKeys[pygame.K_UP] and board.y > 40 + board.vel: board.y -= board.vel board.right = False board.left = False board.up = True board.down = False elif arrowKeys[pygame.K_DOWN] and board.y < 450 - board.height - board.vel: board.y += board.vel board.right = False board.left = False board.up = False board.down = True elif arrowKeys[pygame.K_ESCAPE]: run = False else: board.right = False board.left = False board.up = False board.down = False board.walkCount = 0 # 统一渲染流程:清除窗口 → 绘制地图 → 绘制角色 window.fill((0, 0, 0)) # 清除窗口,避免角色移动留下残影 multilineRender(window, text, 20, 20, myfont, (255, 255, 255)) board.redrawGameWindow(window) # 统一更新显示 pygame.display.update() # 退出程序 pygame.quit()
关键修复点说明
- 移除嵌套循环:所有逻辑都在一个主循环中执行,确保输入处理、渲染操作同步进行。
- 统一渲染顺序:每次循环先清除窗口,再绘制地图,最后绘制角色,保证角色显示在地图上方。
- 单一显示更新:只在主循环末尾调用一次
pygame.display.update(),确保所有绘制完成后再刷新屏幕。 - 修复退出逻辑:按下ESC或点击关闭按钮时,直接退出主循环,再执行
pygame.quit(),避免销毁显示表面后还执行绘制操作。
这样修改后,你的Sprite应该能正常显示,退出时的报错也会消失。
内容的提问来源于stack exchange,提问作者Haqeem Wan
相关产品推荐
相关产品推荐

