You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame游戏:主循环改为函数后玩家图像切换失效求助

《Cannibal Cars》玩家图像切换失效问题解决

问题描述

我正在开发一款名为《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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 14:54:22