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

Pygame碰撞时如何在保持比例前提下正确放大玩家水母图像

问题根本原因

你在反复缩放已被压缩过的水母帧素材:初始加载时你已经把所有水母帧缩放到了30x30的尺寸存入列表,每次scaleup时都在上一次缩放后的素材基础上再次放大,多次小幅度缩放的插值误差会不断累积,最终导致图像宽高比变形、尺寸超出预期。当每次scale增幅≥10时,缩放总次数少,误差累积不明显,所以问题看起来更轻。
另外还存在两个隐含问题:

  • 遍历帧列表时一边删除一边插入,很容易出现索引错位导致帧错误
  • 水母放大后碰撞框colRect没有同步更新尺寸,碰撞检测会不准

修复方案

  1. 提前保留原始尺寸的水母素材,每次缩放都从原始素材生成,避免误差累积
  2. 修正帧列表的缩放逻辑,不要在循环中修改原列表
  3. 缩放后同步更新碰撞框尺寸

修改后的代码示例

素材加载部分(替换原有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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 20:36:05