Pygame游戏:主循环改为函数后玩家图像切换失效求助
问题描述
我正在开发一款名为《Cannibal Cars》的游戏,玩家操控汽车在开放道路上行驶并吞噬其他汽车。按下空格键可让玩家汽车切换形态进行吞噬,松开任意按键恢复原形态。为实现标题界面,我将主游戏循环改为函数,但此后吞噬功能正常,玩家图像切换却失效了。问题涉及底部的三个函数,求解答。
import pygame import random import math from pygame import mixer pygame.init() # Window screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption("Cannibal Cars") background = pygame.image.load("backgrpund.png") clock = pygame.time.Clock() green = 50, 168, 80 bright_green = 50, 250, 80 black = 0, 0, 0 # background sound mixer.music.load('background music.wav') mixer.music.play(-1) # player animation playerImg = pygame.image.load("player.png").convert_alpha() playerX = 200 playerY = 200 playerX_change = 0 playerY_change = 0 player_state = "nice" # enemy enemyImg = [] enemyX = [] enemyY = [] enemyX_change = [] num_of_enemies = 30 for i in range(num_of_enemies): enemyImg.append(pygame.image.load("enemy.png")) enemyX.append(random.randint(400, 750)) enemyY.append(random.randint(0, 550)) enemyX_change.append(1) # In game text score_value = 0 font = pygame.font.Font('freesansbold.ttf', 32) textX = 10 textY = 10 game_over_font = pygame.font.Font('freesansbold.ttf', 64) def show_score(x, y): score = font.render("Score:" + str(score_value), True, (255, 255, 255)) screen.blit(score, (x, y)) def text_object(text, font): textSurface = font.render(text, True, black) return textSurface, textSurface.get_rect() def player(x, y): screen.blit(playerImg, (x, y)) def enemy(x, y): screen.blit(enemyImg[i], (x, y)) def isCollision(enemyX, enemyY, playerX, playerY): distance = math.sqrt((math.pow(enemyX - playerX, 2)) + (math.pow(enemyY - playerY, 2))) if distance < 27: return True else: return False def game_over(): game_over_text = game_over_font.render("GAME OVER: ", True, (255, 255, 255)) screen.blit(game_over_text, (200, 250)) game_intro() def button(msg,x,y,w,h,ic,ac,action=None): mouse = pygame.mouse.get_pos() click = pygame.mouse.get_pressed() if x + w > mouse[0] > x and y + h > mouse[1] > y: pygame.draw.rect(screen, ac, (x, y, w, h)) if click[0] == 1 and action != None: if action == "play": game_loop() else: pygame.draw.rect(screen, ic, (x, y, w, h)) textSurf, textRect = text_object(msg, font) textRect.center = ((x + (w / 2)), (y + h / 2)) screen.blit(textSurf, textRect) def game_intro(): intro = True while intro: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() screen.fill("white") font = pygame.font.Font('freesansbold.ttf', 32) intro_text = font.render("Cannibal Cars", True, (0, 0, 0)) controls_text = font.render("Arrow keys to move", True, (0, 0, 0)) controls_text2 = font.render("Space bar to transform", True, (0, 0, 0)) controls_text3 = font.render("Stop pressing any key to return to normal", True, (0, 0, 0)) screen.blit(intro_text, (300, 100)) screen.blit(controls_text, (20, 150)) screen.blit(controls_text2, (20, 200)) screen.blit(controls_text3, (20, 250)) button("Play", 300, 450, 100, 50, green, bright_green, "play") pygame.display.update() clock.tick(15) def game_loop(): playerImg = pygame.image.load("player.png").convert_alpha() playerX = 200 playerY = 200 playerX_change = 0 playerY_change = 0 player_state = "nice" score_value = 0 playerImg2 = pygame.image.load("cannibal car.png").convert_alpha() running = True while running: screen.fill((0, 0, 0)) screen.blit(background, (0, 0)) for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # controls if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: playerX_change = -0.8 playerImg = pygame.transform.flip(playerImg, True, False) if event.key == pygame.K_RIGHT: playerX_change = 0.8 if event.key == pygame.K_UP: playerY_change = -0.8 if event.key == pygame.K_DOWN: playerY_change = 0.8 if playerX_change < 0: playerImg = pygame.transform.flip(playerImg, True, False) if event.key == pygame.K_SPACE: playerImg = playerImg2 player_state = "cannibal" if event.type == pygame.KEYUP: playerX_change = 0 playerY_change = 0 playerImg = pygame.image.load("player.png") player_state = "nice" # player movement player(playerX, playerY) playerX += playerX_change playerY += playerY_change if playerX <= 0: playerX = 0 elif playerX >= 770: playerX = 770 if playerY <= 0: playerY = 0 elif playerY >= 570: playerY = 570 # enemy movement for i in range(num_of_enemies): enemyX[i] += enemyX_change[i] if enemyX[i] <= 0: enemyX_change[i] = 1 elif enemyX[i] >= 736: enemyX_change[i] = -1 # Collision with enemy enemy(enemyX[i], enemyY[i]) collision = isCollision(enemyX[i], enemyY[i], playerX, playerY) show_score(textX, textY) if collision: if player_state == "cannibal": cannibal_sound = mixer.Sound('Cannibal car.wav') cannibal_sound.play() enemyX[i] = (random.randint(0, 800)) enemyY[i] = (random.randint(0, 600)) score_value += 1 else: game_over() pygame.display.update() game_intro() game_loop() pygame.display.update() pygame.quit() quit()
问题根源与修复方案
1. 变量作用域冲突(核心问题)
你在全局作用域定义了playerImg,但在game_loop函数内部又重新声明了同名的局部变量playerImg。而绘制玩家的player()函数调用的是全局的playerImg,完全没用到game_loop里修改的局部变量,所以图像切换操作根本不会反映到画面上。
修复方式二选一:
方式一:在
game_loop里声明使用全局变量
在game_loop开头添加global playerImg,这样函数内的修改会直接作用于全局变量:def game_loop(): global playerImg, playerX, playerY, playerX_change, playerY_change, player_state, score_value # 移除局部的playerImg定义,使用全局已加载的图像 playerX = 200 playerY = 200 playerX_change = 0 playerY_change = 0 player_state = "nice" score_value = 0 playerImg2 = pygame.image.load("cannibal car.png").convert_alpha() # ... 后续代码不变方式二:让
player函数接收图像参数
修改player函数,让它接收要绘制的图像,避免依赖全局变量:def player(x, y, img): screen.blit(img, (x, y))然后在
game_loop里调用时传入局部的playerImg:player(playerX, playerY, playerImg)
2. KEYUP事件逻辑错误
当前代码中,只要松开任意按键(比如方向键),就会立刻把playerImg恢复为原形态。这会导致按住空格+方向键时,松开方向键就触发恢复,看起来像是切换失效,不符合“松开任意按键(指所有按键都松开)恢复原形态”的需求。
修复方案:
修改KEYUP事件处理逻辑,只在没有任何按键被按住时才恢复原形态:
# 替换原有的KEYUP代码块 if event.type == pygame.KEYUP: # 单独处理方向键的速度重置 if event.key in (pygame.K_LEFT, pygame.K_RIGHT): playerX_change = 0 if event.key in (pygame.K_UP, pygame.K_DOWN): playerY_change = 0 # 检查当前是否有任何按键处于按下状态 keys_pressed = pygame.key.get_pressed() if not any(keys_pressed): # 没有按键按住时恢复原形态 playerImg = pygame.image.load("player.png").convert_alpha() player_state = "nice"
3. 额外的缩进错误(game_intro函数)
game_intro里的controls_text等变量定义在while intro:循环外面,这会导致这些文本只初始化一次,且不会在每次循环中更新。需要把这些代码缩进,放到循环内部:
def game_intro(): intro = True while intro: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() screen.fill("white") font = pygame.font.Font('freesansbold.ttf', 32) intro_text = font.render("Cannibal Cars", True, (0, 0, 0)) # 以下三行缩进,放到while循环内 controls_text = font.render("Arrow keys to move", True, (0, 0, 0)) controls_text2 = font.render("Space bar to transform", True, (0, 0, 0)) controls_text3 = font.render("Stop pressing any key to return to normal", True, (0, 0, 0)) screen.blit(intro_text, (300, 100)) screen.blit(controls_text, (20, 150)) screen.blit(controls_text2, (20, 200)) screen.blit(controls_text3, (20, 250)) button("Play", 300, 450, 100, 50, green, bright_green, "play") pygame.display.update() clock.tick(15)
内容的提问来源于stack exchange,提问作者Tamaki Gower

