Pygame项目Sprite抖动、动画失效问题求助
Pygame项目问题求助:Sprite抖动+精灵表动画失效
运行Pygame项目时遇到两个核心问题:
- Sprite角色持续上下抖动
- 从精灵表导入的动画无法正常播放
以下是Fighter类的代码:
def load_images(self, sprite_sheet, animation_steps): #extract the certain animation images from spritesheet animation_list = [] for y, animation in enumerate(animation_steps): temporary_img_list = [] for x in range(animation): temporaryimg = sprite_sheet.subsurface(x , y , self.size, self.size) temporary_img_list.append(pygame.transform.scale(temporaryimg, (self.size * self.image_scale, self.image_scale * self.size))) animation_list.append(temporary_img_list) print(animation_list) return animation_list def move(self, screen_base, screen_height, surface, target): speed = 10 gravity = 2 dx = 0 dy = 0 self.running = False self.attack_type = 0 #key-presses recall key = pygame.key.get_pressed() = pygame.key.get_pressed() #can only happen if no other attack is occuring if self.attacking == False: #movement defined here if key[pygame.K_a]: dx = -speed self.running = True if key[pygame.K_d]: dx = speed self.running = True #jump is defined here if key[pygame.K_w] and self.jump == False: self.vel_y = -30 self.jump = True #attack is defined here if key[pygame.K_k] or key[pygame.K_j]: self.attack(surface, target) #determine which attack type was used when the key was pressed if key[pygame.K_k]: self.attack_type = 1 if key[pygame.K_j]: self.attack_type = 2 #apply gravity for the jumps self.vel_y += gravity dy += self.vel_y #this makes sure that the character does not go off the screen if self.rect.left + dx < 0: dx = -self.rect.left if self.rect.right + dx > screen_base: dx = screen_base - self.rect.right if self.rect.bottom + dy > screen_height - 207: self.vel_y = 0 self.jump = False dy = screen_height - 207 - self.rect.bottom #ensures the players face each other if target.rect.centerx > self.rect.centerx: self.flip = False else: self.flip = True #apply the attack cooldown to balance the amount of attacks possible if self.attack_cooldown > 0: self.attack_cooldown -= 1 #update the player position constantly self.rect.x += dx self.rect.y += dy #handle the animation updates def update(self): #check what action the player is currently doing if self.health <= 0: self.health = 0 self.alive = False self.update_action(6) elif self.hit == True: self.update_action(5) elif self.attacking == True: if self.attack_type == 1: self.update_action(5) # 3 = Attack elif self.attack_type == 2: self.update_action(6) # 4 = Attack2 elif self.jump == True: self.update_action(7) # 7 = Jump elif self.running == True: self.update_action(2) # 2 = Run else: self.update_action(0) # 0 = Idle animation_cooldown = 50 #update the image self.image = self.animation_list[self.action][self.frameindex] #check if enough time has passed since the last update if pygame.time.get_ticks() - self.update_time > animation_cooldown: self.frameindex += 1 self.updatetime = pygame.time.get_ticks() #check if the animation has finished if self.frameindex >= len(self.animation_list[self.action]): #if the player is dead end the animation if self.alive == False: self.frameindex = len(self.animation_list[self.action]) - 1 else: self.frameindex = 0 #check if an attack was executed if self.action == 5 or self.action == 6: self.attacking = False self.attack_cooldown = 20 #check if damage was taken if self.action == 7: self.hit = False #if the player was in the middle on an attack, then the attack is stopped self.attacking= False self.attack_cooldown = 20 def attack(self, surface, target): if self.attack_cooldown == 0: self.attacking = True attacking_rect = pygame.Rect(self.rect.centerx - (2 * self.rect.width * self.flip), self.rect.y, 2 * self.rect.width, self.rect.height) if attacking_rect.colliderect(target.rect): target.health -= 5 target.hit = True pygame.draw.rect(surface, (0, 255, 0), attacking_rect) def update_action(self, new_action): #check if the new action is different to the previous one if new_action != self.action: self.action = new_action #update the animation settings self.frameindex = 0 self.update_time = pygame.time.get_ticks() def draw(self, surface): img = pygame.transform.flip(self.image, self.flip, False) #pygame.draw.rect(surface,(255, 0, 0), self.rect) surface.blit(img, (self.rect.x - (self.offset[0] * self.image_scale), self.rect.y - (self.offset[1] * self.image_scale)))
问题排查与修复方案
一、Sprite上下抖动问题
修复键盘输入赋值错误
move方法里的key = pygame.key.get_pressed() = pygame.key.get_pressed()是语法错误,改成:key = pygame.key.get_pressed()修正地面碰撞逻辑,避免位置反复跳动
原代码通过计算dy间接调整位置,容易因重力累加导致角色在地面上下抖动,改成直接固定角色底部到地面:if self.rect.bottom + dy > screen_height - 207: self.vel_y = 0 self.jump = False # 直接将角色底部贴到地面,消除抖动 self.rect.bottom = screen_height - 207 dy = 0 # 重置dy,避免额外位移
二、精灵表动画失效问题
修正精灵表帧截取坐标
load_images里的subsurface参数错误,没有按单帧尺寸计算坐标,改成:temporaryimg = sprite_sheet.subsurface(x * self.size, y * self.size, self.size, self.size)(每帧的起始x坐标是
x*self.size,y坐标是y*self.size,对应精灵表的行列位置)修复动画更新的变量名笔误
update方法里的self.updatetime = pygame.time.get_ticks()少了下划线,应该是:self.update_time = pygame.time.get_ticks()这个笔误会导致动画冷却逻辑完全失效,帧永远无法推进。
统一动作状态映射,避免逻辑混乱
原代码中动作编号的注释和实际赋值不匹配(比如攻击注释是3,实际用5),建议定义常量统一管理:# 在类中或全局定义动作常量 ACTION_IDLE = 0 ACTION_RUN = 2 ACTION_JUMP = 3 ACTION_ATTACK1 = 4 ACTION_ATTACK2 = 5 ACTION_HIT = 6 ACTION_DEAD = 7然后在
update方法中替换数字为常量,比如:elif self.jump == True: self.update_action(ACTION_JUMP)修正动画结束后的状态重置逻辑
原代码中攻击动作的判断条件if self.action ==5 or self.action ==6需要和实际的攻击动作编号匹配,否则攻击状态无法重置,角色会一直卡在攻击动画里。比如如果攻击1的动作编号是4,攻击2是5,就改成:if self.action == ACTION_ATTACK1 or self.action == ACTION_ATTACK2: self.attacking = False self.attack_cooldown = 20
内容的提问来源于stack exchange,提问作者Sofian Ghailane
相关产品推荐
相关产品推荐

