Pygame游戏结束功能实现问题:分数达标后无法停止及屏幕闪烁
嘿,我看你这个收集类小游戏遇到了两个棘手的问题:分数到100后游戏没法停止,还出现了屏幕闪烁的情况。咱们一步步来搞定这些问题!
问题根源分析
1. 游戏无法停止
你当前的代码里,当score >= 100时调用endoflevel1(),但Pygame(或者你用的Pygame Zero框架)的update()和draw()函数会持续循环执行——哪怕你显示了结束界面,后续的update()还是会继续处理角色移动、碰撞逻辑,draw()也会重新绘制游戏界面,直接把结束界面覆盖掉,所以你根本看不到结束状态,游戏也停不下来。
2. 屏幕闪烁
闪烁的原因是你在endoflevel1()里手动调用了pygame.display.flip(),但框架本身已经在自动处理屏幕刷新了,手动刷新和自动刷新冲突,就会导致画面闪烁。另外,draw()里的screen.clear()和screen.blit()的顺序如果处理不好,也可能加重闪烁。
解决方案(不用while循环,用状态控制)
我们不需要额外加while循环,框架本身已经有事件循环了,只需要加一个游戏状态变量来控制游戏处于“运行中”还是“已结束”状态,然后在update()和draw()里根据这个状态执行不同逻辑。
步骤1:添加游戏状态变量
在全局变量区域添加:
game_active = True # 控制游戏是否处于运行状态
步骤2:修改update函数,让游戏结束时停止逻辑
在update()函数开头加上判断,游戏结束时直接返回,不再处理后续逻辑:
def update(): global score, game_active if not game_active: return # 游戏已结束,跳过所有游戏逻辑 # 下面保留原来的移动、碰撞逻辑...
步骤3:修改draw函数,根据状态绘制界面
把结束界面的绘制逻辑移到draw()里,代替原来的endoflevel1()函数,这样框架能统一处理刷新,避免闪烁:
def draw(): if game_active: screen.clear() screen.blit("background", (0,0)) apple.draw() pear.draw() plum.draw() donut.draw() ice.draw() chips.draw() happysmiley.draw() screen.draw.text("Punkte: " + str(score), (700, 5), color = "black") else: # 绘制结束界面 screen.fill("green") screen.draw.text("Game Over: Du hast das 1. Level erfolgreich abgeschlossen!", topleft=(100,350), fontsize=30)
步骤4:修改分数达标后的逻辑
原来的endoflevel1()可以删掉,改成直接设置game_active = False:
if score >= 100: game_active = False # 可以在这里添加结束音效、停止背景音乐等逻辑 pygame.mixer.music.stop()
步骤5:修复碰撞检测的小bug
你代码里chips的碰撞判断写错了,把chips.x写成了chips.y:
# 错误代码: if happysmiley.collidepoint (chips.y, chips.y): # 改成: if happysmiley.collidepoint(chips.x, chips.y):
额外优化:简化重复的食物移动逻辑
你现在每个食物的移动和重置逻辑都是重复的,可以把所有食物放到一个列表里,用循环处理,让代码更简洁:
# 替换原来的单个Actor定义 foods = [ Actor("apple"), Actor("pear"), Actor("plum"), Actor("donut"), Actor("ice"), Actor("chips") ] # 初始化所有食物的位置 for food in foods: food.pos = randint(0, 800), randint(-800, 0) # 在update()里替换原来的多个if判断 for food in foods: if food.y < 800: food.y += 4 else: food.pos = randint(0, 800), randint(-800, 0)
修改后的完整代码
from random import randint import pygame WIDTH = 800 HEIGHT = 800 # 初始化食物列表,简化重复代码 foods = [ Actor("apple"), Actor("pear"), Actor("plum"), Actor("donut"), Actor("ice"), Actor("chips") ] for food in foods: food.pos = randint(0, 800), randint(-800, 0) happysmiley = Actor("happysmiley") happysmiley.pos = 300, 750 score = 0 game_active = True # 游戏状态控制变量 background = pygame.image.load("images\\background.png") pygame.mixer.init() pygame.mixer.music.load("music\\funmusic.mp3") pygame.mixer.music.play(-1) def draw(): if game_active: screen.clear() screen.blit("background", (0,0)) for food in foods: food.draw() happysmiley.draw() screen.draw.text("Punkte: " + str(score), (700, 5), color = "black") else: screen.fill("green") screen.draw.text("Game Over: Du hast das 1. Level erfolgreich abgeschlossen!", topleft=(100,350), fontsize=30) def update(): global score, game_active if not game_active: return # 游戏结束,停止所有逻辑 # 处理食物移动 for food in foods: if food.y < 800: food.y += 4 else: food.pos = randint(0, 800), randint(-800, 0) # 处理玩家移动 if keyboard.left: happysmiley.x -= 5 elif keyboard.right: happysmiley.x += 5 # 处理碰撞逻辑 for food in foods: if happysmiley.collidepoint(food.x, food.y): # 根据食物类型更新分数和音效 if food.image == "apple": score += 2 effect = pygame.mixer.Sound("sounds\\bonus.wav") elif food.image in ["pear", "plum"]: score += 1 effect = pygame.mixer.Sound("sounds\\bonus.wav") else: # donut, ice, chips score -= 1 effect = pygame.mixer.Sound("sounds\\no.wav") effect.play() # 碰撞后重置食物位置 food.pos = randint(0, 800), randint(-800, 0) # 检查是否达标结束游戏 if score >= 100: game_active = False pygame.mixer.music.stop()
这样修改后,游戏分数到100时会立刻停止所有游戏逻辑,显示结束界面,而且不会出现闪烁问题啦!
内容的提问来源于stack exchange,提问作者yellowcake

