Sprite 显示但不会切换动画或在 PyGame 中随按键移动

Sprite displays but won't switch animations or move with key presses in PyGame

构建一个简单的 PyGame,其中我需要玩家精灵根据箭头键的按下来移动和更改图像。我在 Sprite1 class 中添加了 facing 函数,并在游戏循环中按键的 if 语句中调用它,希望它会在每次按下键时改变图像,但它似乎不想更新精灵的按键后的图像。我面对的功能有问题吗?还是用别的东西?

import pygame 
pygame.init() 

#game Window 
screen_width = 800
screen_height = 400

screen = pygame.display.set_mode((screen_width, screen_height)) 
pygame.display.set_caption('Warrior Quest') 

#game variables
main_menu = True

#background image
background_img =  pygame.image.load('background.png')
#button images 
start_img = pygame.image.load('startbutton.PNG')
cancel_img = pygame.image.load('cancelbutton.PNG')
title_img = pygame.image.load('warriorquestTile.PNG')

#background function 
def draw_bg(): 
  screen.blit(background_img, (0,0)) 

 
class Sprite1(pygame.sprite.Sprite):
  def __init__(self): 
    super().__init__()  
    self.faceUp = True
    self.faceDown = False
    self.faceLeft = False 
    self.faceRight = False
    self.image = pygame.image.load('player.png').convert_alpha()
    self.rect = self.image.get_rect()
  
  def draw(self):
    screen.blit(self.image, self.rect)

  def facing(self):
    if self.faceUp == True:
      self.image = pygame.image.load('player.png').convert_alpha()
      self.rect.w = self.image.get_rect().w
      self.rect.h = self.image.get_rect().h
    elif self.faceDown == True:
      self.image = pygame.image.load('playerDown.png').convert_alpha()
      self.rect = self.image.get_rect()
    elif self.faceLeft == True:
      self.image = pygame.image.load('playerLeft.png').convert_alpha()
      self.rect = self.image.get_rect()
    elif self.faceRight == True:
      self.image = pygame.image.load('playerRight.png').convert_alpha()
      self.rect = self.image.get_rect()
  

#setup player 
player = Sprite1()
player.rect.x = 400
player.rect.y = 380

class Button():
  def __init__(self,x,y,image):
    self.image = image
    self.rect = self.image.get_rect() 
    self.rect.x = x 
    self.rect.y = y 
    self.clicked = False 
   
  def draw(self):
    action = False
    
    #get mouse position
    pos = pygame.mouse.get_pos() 
    
    if self.rect.collidepoint(pos):
      if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
        action = True 
        self.clicked = True 

    if pygame.mouse.get_pressed()[0] == 0:
      self.clicked = False 

    #draw Button 
    screen.blit(self.image, self.rect) 

    return action

 
#create buttons 
start_button = Button(screen_width // 2 -350, screen_height // 2, start_img) 
cancel_button = Button(screen_width // 2 + 150, screen_height // 2, cancel_img)
title_button = Button(300,400,title_img)
#game loop running 
running = True
while running:
  
  draw_bg()
  if main_menu == True: 
    
    if start_button.draw():
      main_menu = False
    if cancel_button.draw():
      running = False 
  else:  
    player.draw()
   
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player.rect.x>5:
      player.faceLeft = True 
      player.facing()
      player.rect.x -= 5
    if keys[pygame.K_RIGHT] and player.rect.x<790:
      player.faceRight = True 
      player.facing()
      player.rect.x += 5
    if keys[pygame.K_UP] and player.rect.y>10:
      player.faceUp = True 
      player.facing()
      player.rect.y -= 5
    if keys[pygame.K_DOWN]and player.rect.y<395:
      player.faceDown = True 
      player.facing()
      player.rect.y += 5
  
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      running = False
  
  pygame.display.update() 
pygame.quit()  

    

每次更新精灵时,都会将其矩形重置为图像的矩形:

    if self.faceUp == True:
      self.image = pygame.image.load('player.png').convert_alpha()
      self.rect = self.image.get_rect()

相反,只更新宽度和高度:

    if self.faceUp == True:
      self.image = pygame.image.load('player.png').convert_alpha()
      self.rect.w = self.image.get_rect().w
      self.rect.h = self.image.get_rect().h

pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. A Surface is blit at a position on the screen. The position of the rectangle can be specified by a keyword argument. For example, the center of the rectangle can be specified with the keyword argument center. These keyword argument are applied to the attributes of the pygame.Rect before it is returned (see pygame.Rect 关键字参数的完整列表)。

通过保持矩形的中心位置来保持精灵的位置:

if self.faceUp == True:
    self.image = pygame.image.load('player.png').convert_alpha()
    self.rect = self.image.get_rect(center = self.rect.center)

此外,不要在应用程序循环中加载图像。加载图像非常耗时,因为必须读取和解释图像文件。在应用程序开始时加载一次图像:

设置新的face*属性是不够的,您还必须重新设置其他face*属性。我建议使用具有不同状态的单个属性 face

class Sprite1(pygame.sprite.Sprite):
  def __init__(self): 
    super().__init__()  
    self.player_img = pygame.image.load('player.png').convert_alpha()
    self.player_down_img = pygame.image.load('playerDown.png').convert_alpha()
    self.player_left_img = pygame.image.load('playerLeft.png').convert_alpha()
    self.player_right_img = pygame.image.load('playerRight.png').convert_alpha()
    self.face = "up" 
    self.image = self.player_img
    self.rect = self.image.get_rect()
  
  def draw(self):
    screen.blit(self.image, self.rect)

  def facing(self):
    if self.face == "up" :
      self.image = self.player_img
    elif self.face == "down":
      self.image = self.player_down_img
    elif self.face == "left":
      self.image = self.player_left_img
    elif self.face == "right":
      self.image = self.player_right_img
    self.rect = self.image.get_rect(center = self.rect.center)
running = True
while running:
    # [...]

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player.rect.x>5:
      player.face = "up"
      player.facing()
      player.rect.x -= 5
    if keys[pygame.K_RIGHT] and player.rect.x<790:
      player.face = "down" 
      player.facing()
      player.rect.x += 5
    if keys[pygame.K_UP] and player.rect.y>10:
      player.face = "left"
      player.facing()
      player.rect.y -= 5
    if keys[pygame.K_DOWN]and player.rect.y<395:
      player.face = "right": 
      player.facing()
      player.rect.y += 5