Pygame精灵无动画故障排查及代码修正请求
Pygame Sprite动画静态问题修复
问题原因
- 动画帧被强制重置:
Player类的draw方法中,每次绘制时都会将self.sprite重新赋值为idle动画的第一帧,完全覆盖了update_sprite方法计算出的动画帧,导致动画无法播放。 - 逻辑调用顺序错误:主循环中先执行
player.loop()再处理按键输入,使得移动速度的更新滞后一帧,移动响应延迟。
修正后的代码
import os import random import math import pygame from os import listdir from os.path import isfile, join pygame.init() pygame.display.set_caption("Platformer") #set the caption at the top of the window BG_COLOR = (255,255,255) #White background, dont need it anymore WIDTH, HEIGHT = 1000, 640 #screen dimensions FPS = 60 PLAYER_VEL = 5 # the speed of the player window = pygame.display.set_mode((WIDTH, HEIGHT)) #set the window with sizes def flip(sprites): return [pygame.transform.flip(sprite, True, False) for sprite in sprites] def load_sprite_sheets(dir1, dir2, width, height, direction=False): path = join("assets", dir1, dir2) images = [f for f in listdir(path) if isfile(join(path, f))] #if f is a file put in the images list all_sprites = {} for image in images: sprite_sheet = pygame.image.load(join(path, image)).convert_alpha() #loaded transparent bg image sprites = [] for i in range(sprite_sheet.get_width() // width): surface = pygame.Surface((width, height), pygame.SRCALPHA, 32) rect = pygame.Rect(i * width, 0, width, height) surface.blit(sprite_sheet, (0, 0), rect) sprites.append(pygame.transform.scale2x(surface)) if direction: all_sprites[image.replace(".png", "") + "_right"] = sprites all_sprites[image.replace(".png", "") + "_left"] = flip(sprites) else: all_sprites[image.replace(".png", "")] = sprites return all_sprites class Player(pygame.sprite.Sprite): #sprite is useful for perfect pixel collision COLOR = (0,0,255) GRAVITY = 1 SPRITES = load_sprite_sheets("MainCharacters" , "MaskDude", 32 , 32 , True) ANIMATION_DELAY = 3 def __init__(self, x,y, width , height): self.rect = pygame.Rect(x,y,width,height) self.x_vel = 0 self.y_vel = 0 self.mask = None self.direction = "left" # to record which animation to show self.animation_count = 0 # self.fall_count = 0 # 初始化默认 sprite self.sprite = self.SPRITES["idle_"+self.direction][0] def move(self,dx,dy): self.rect.x += dx self.rect.y += dy #here we draw only the motion calculated in the next functions def move_left(self, vel): self.x_vel = -vel if self.direction != "left": self.direction = "left" self.animation_count = 0 def move_right(self, vel): self.x_vel = vel if self.direction != "right": self.direction = "right" self.animation_count = 0 def loop(self , fps): # self.y_vel += min(1 , (self.fall_count/fps) * self.GRAVITY) self.move(self.x_vel,self.y_vel) self.fall_count += 1 self.update_sprite() def update_sprite(self): #is about changing the sprite shape to look walking sprite_sheet = "idle" if self.x_vel !=0: sprite_sheet = "run" sprite_sheet_name = sprite_sheet + "_" + self.direction sprites = self.SPRITES[sprite_sheet_name] sprite_index = (self.animation_count // self.ANIMATION_DELAY) % len(sprites) #set new index every ANIMATION_DELAY = 5 self.sprite = sprites[sprite_index] self.animation_count += 1 def draw(self, win): # 移除强制重置sprite的代码,直接使用update_sprite设置好的帧 win.blit(self.sprite , (self.rect.x , self.rect.y)) def get_background(name): #name is bg image, this create the bg image position list image = pygame.image.load(join("assets", "Background", name)) _, _, width, height = image.get_rect() tiles = [] #list of tles I need to fil my window bg for i in range(WIDTH//width + 1): for j in range (HEIGHT // height+1): pos = tuple([i * width , j*height]) # convert list into tuple tiles.append(pos) return tiles, image # now I now the list of positions to fill the bg and the exact file to use def draw(window, background, bg_image, player): for tile in background: window.blit(bg_image, tile) # drawing the image at every position player.draw(window) pygame.display.update() def handle_move(player): #check keys and collision keys = pygame.key.get_pressed() player.x_vel = 0; #as moveleft change the velocity we have to change it to zero so w if keys[pygame.K_LEFT]: player.move_left(PLAYER_VEL) if keys[pygame.K_RIGHT]: player.move_right(PLAYER_VEL) def main(window): clock = pygame.time.Clock() background, bg_image = get_background("Blue.png") player = Player(100,100,50,50) run = True while(run): clock.tick(FPS) #fix the refresh rate to this otherwise it will be dpending on the computer power for event in pygame.event.get(): if event.type == pygame.QUIT: #if teh program detect an event of the user Quiting the game run = False break # 先处理按键输入更新速度,再执行loop进行移动和动画更新 handle_move(player) player.loop(FPS) draw(window, background, bg_image, player) pygame.quit() quit() #quiting the python itself if __name__ == "__main__": main(window) #when we run the file go to the main function with this arg
关键修改点
- 在
Player.__init__中初始化默认的self.sprite,避免绘制时出现未定义的情况。 - 删除
Player.draw中self.sprite = self.SPRITES["idle_"+self.direction][0]这行代码,让update_sprite控制的动画帧正常显示。 - 调整主循环中
handle_move和player.loop的调用顺序,确保移动速度是最新的按键输入值。
内容的提问来源于stack exchange,提问作者aharbiy
相关产品推荐
相关产品推荐

