Pygame碰撞时如何在保持比例前提下正确放大玩家水母图像
问题根本原因
你在反复缩放已被压缩过的水母帧素材:初始加载时你已经把所有水母帧缩放到了30x30的尺寸存入列表,每次scaleup时都在上一次缩放后的素材基础上再次放大,多次小幅度缩放的插值误差会不断累积,最终导致图像宽高比变形、尺寸超出预期。当每次scale增幅≥10时,缩放总次数少,误差累积不明显,所以问题看起来更轻。
另外还存在两个隐含问题:
- 遍历帧列表时一边删除一边插入,很容易出现索引错位导致帧错误
- 水母放大后碰撞框
colRect没有同步更新尺寸,碰撞检测会不准
修复方案
- 提前保留原始尺寸的水母素材,每次缩放都从原始素材生成,避免误差累积
- 修正帧列表的缩放逻辑,不要在循环中修改原列表
- 缩放后同步更新碰撞框尺寸
修改后的代码示例
素材加载部分(替换原有img0~img8的加载逻辑)
import pygame, math, time pt = time.time() speed = 40 # 提前加载原始尺寸的水母素材,不要提前缩放 original_frames = [ pygame.image.load(f"assets/glow{i}.png").convert_alpha() for i in range(9) ] pygame.display.set_mode((800, 500))
Glow类修改
class Glow(): rot = 0 rotp = 1 xsp = 0 ysp = 0 def __init__(self, x, y, scale): self.x, self.y = x, y self.scale = scale # 初始化时从原始素材缩放得到当前帧列表 self.list = [ pygame.transform.scale(img, (self.scale, self.scale)) for img in original_frames ] self.current = 0 self.image = self.list[int(self.current)] self.rect = self.image.get_rect(center = (x, y)) # 初始化碰撞框 self.colRect = pygame.rect.Rect((0, 0), (self.rect.width/3, self.rect.height/3)) self.colRect.center = self.rect.center def update(self, x, y, accex): global pt, speed now = time.time() dt = now - pt pt = now self.rect = self.image.get_rect(center = (x, y)) if pygame.key.get_pressed()[pygame.K_UP] or accex: # 动画逻辑不变 self.current += dt*5 if self.current >= len(self.list): self.current = 0 self.image = pygame.transform.rotate(self.list[int(self.current)], self.rot) self.rect = self.image.get_rect(center = (x, y)) self.colRect.center = self.rect.center # 移动逻辑不变 self.rotr = math.radians(self.rot) self.ysp = math.cos(self.rotr) self.xsp = math.sin(self.rotr) self.x -= self.xsp*dt*speed self.y -= self.ysp*dt*speed if not accex: if pygame.key.get_pressed()[pygame.K_LEFT]: self.rot += math.pi*dt*7 if pygame.key.get_pressed()[pygame.K_RIGHT]: self.rot -= math.pi*dt*7 if accex: speed += dt*10 def scaleup(self): self.scale += 2 # 直接从原始素材生成新的帧列表,避免误差累积 self.list = [ pygame.transform.scale(img, (self.scale, self.scale)) for img in original_frames ] # 更新当前显示的图片 self.image = pygame.transform.rotate(self.list[int(self.current)], self.rot) self.rect = self.image.get_rect(center = (self.x, self.y)) # 同步更新碰撞框尺寸 self.colRect = pygame.rect.Rect((0, 0), (self.rect.width/3, self.rect.height/3)) self.colRect.center = self.rect.center
游戏循环部分可选优化(避免遍历食物列表时删元素出错)
W, H = 800, 500 sc = pygame.display.set_mode((W, H)) score = 0 score_x, score_y = 10, 10 font = pygame.font.SysFont("calibri", 30) score_text = font.render("0", True, (255,255,255)) score_rect = score_text.get_rect(topleft = (score_x, score_y)) if lvl0: glow.update(glow.x, glow.y, accex) sc.fill((0,0,0)) # 倒序遍历避免删除元素时漏判 for i in range(len(Food.food_list)-1, -1, -1): food = Food.food_list[i] sc.blit(food.image, (food.x, food.y)) if pygame.Rect.colliderect(glow.colRect, food.rect): del Food.food_list[i] glow.scaleup() score += 3 score_text = font.render(str(score), True, (255,255,255)) score_rect = score_text.get_rect(topleft = (score_x, score_y)) sc.blit(glow.image, glow.rect) sc.blit(label, label_rect) pygame.display.update()
内容的提问来源于stack exchange,提问作者lomstfer
相关产品推荐
相关产品推荐

