Pygame中colliderect未接触时仍触发碰撞问题求助
问题描述
我正在制作一个物品从天而降供玩家收集的系统,但即使角色未触碰物品,colliderect仍会触发碰撞。碰撞仅在角色与物品的X轴重合时发生,Y轴任意位置都会触发。我已尝试打印角色和物品的位置,确认位置与屏幕显示一致,但问题仍存在。
代码片段
import pygame import sys import os import time from pygame.locals import * os.environ["SDL_VIDEO_CENTERED"] = "1" pygame.init() SCREENWIDTH = 580 SCREENHEIGHT = 375 SCREENSIZE = [SCREENWIDTH, SCREENHEIGHT] SCREEN = pygame.display.set_mode(SCREENSIZE) CLOCK = pygame.time.Clock() FPS = 60 jumping = False backgroundImage = pygame.image.load('Images/backgroundImage.jpg') backgroundScaled = pygame.transform.scale(backgroundImage,(580,375)) pygame.display.set_caption("Christmas Game") santaWidth, santaHeight = 93,64 santaImage = pygame.image.load("Images/santa.png") santaScaled = pygame.transform.scale(santaImage,(santaWidth,santaHeight)) santa = pygame.Rect(100,100,santaWidth,santaHeight) font = pygame.font.SysFont("myriadProFont",50) timeText = font.render("", 1,(255,255,255)) startTime = time.time() itemsGroup = pygame.sprite.Group() #IDs 0 = coin, class Item(pygame.sprite.Sprite): def __init__(self,x,y,ID,imageName): super().__init__() self.ID = ID self.image = pygame.image.load(imageName) self.scaledImage = pygame.transform.scale(self.image,(50,50)) self.x = x self.y = y self.rect = self.image.get_rect() self.rect.topleft = (self.x,self.y) def render(self, screen): screen.blit(self.scaledImage,(self.x,self.y)) def collect(self, santa): hit = self.rect.colliderect(santa) if hit: if self.ID == 0: print("Coin") self.kill() def itemGravity(self): if self.y < 370: self.y += 1 self.rect = self.image.get_rect() self.rect.topleft = (self.x,self.y) else: self.kill() print("killed") coin = Item(200,0,0,"Images/coin.png") itemsGroup.add(coin) coin2 = Item(500,0,0,"Images/coin.png") itemsGroup.add(coin2) class Floor(pygame.sprite.Sprite): def __init__(self, width, height, x, y, name): super().__init__() self.image = pygame.image.load(name) self.image = pygame.transform.scale(self.image, (width, height)) self.rect = self.image.get_rect() self.size = width, height self.pos = (x, y) self.rect.topleft = self.pos self.isTouching = False def render(self, display): display.blit(self.image, self.pos) def collision(self,santa): global jumping hit = self.rect.colliderect(santa) if hit and self.isTouching == False: self.isTouching = True elif not hit: self.isTouching = False floorGroup = pygame.sprite.Group() floor = Floor(291,70,-50,305,"Images/floor.webp") floorGroup.add(floor) floor2 = Floor(291,70,330,305,"Images/floor.webp") floorGroup.add(floor2) def adjustTime(): global timeText global jumping newTime = time.time() difference = newTime - startTime if difference > 1: timeText = font.render(time.strftime('%M:%S', time.gmtime(difference)), 1,(255,255,255)) def playerMovement(keyPressed,santa): global jumping if (keyPressed[pygame.K_UP] or keyPressed[pygame.K_w] or keyPressed[pygame.K_SPACE]) and santa.y > 0 and jumping == False: jumping = True santa.y = santa.y - 50 elif(keyPressed[pygame.K_LEFT] or keyPressed[pygame.K_a]) and santa.x > -20: santa.x = santa.x - 5 elif(keyPressed[pygame.K_RIGHT] or keyPressed[pygame.K_d]) and santa.x < 525: santa.x = santa.x + 5 def updateScreen(santa): SCREEN.blit(backgroundScaled, (0, 0)) for floor in floorGroup: floor.render(SCREEN) for item in itemsGroup: item.render(SCREEN) SCREEN.blit(santaScaled,(santa.x,santa.y)) SCREEN.blit(timeText,(250,0)) pygame.display.update() def gravity(santa): global jumping if santa.y < 320: santa.y += 3 elif santa.y == 320: jumping = False else: santa.y = 320 while True: timeDelta = CLOCK.tick(FPS)/1000.0 adjustTime() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() user_input = pygame.key.get_pressed() playerMovement(user_input,santa) gravity(santa) for item in itemsGroup: item.collect(santa) item.itemGravity() for floor in floorGroup: floor.collision(santa) updateScreen(santa) CLOCK.tick(FPS)
问题原因与修复方案
核心问题
碰撞检测异常是因为Item类的rect尺寸错误:
- 初始化和更新时,你用了未缩放的原始图片
self.image创建rect,但实际显示的是缩放后的50x50图片。如果原始图片尺寸远大于50x50,会导致rect的碰撞范围远大于视觉上的物品,从而出现X轴重合就触发碰撞的情况。
修复步骤
- 用缩放后的图片初始化rect
修改Item类的__init__方法,将self.rect = self.image.get_rect()替换为:
self.rect = self.scaledImage.get_rect() # 基于显示的缩放图片生成正确尺寸的rect
- 更新位置时无需重建rect
修改Item类的itemGravity方法,直接更新rect的y坐标,避免每次重建rect导致的尺寸错误:
def itemGravity(self): if self.y < 370: self.y += 1 self.rect.y = self.y # 直接同步rect的y值,保持与显示位置一致 else: self.kill() print("killed")
- 可选优化:统一用Rect属性管理位置
你的santa是Rect对象,但目前直接修改santa.x和santa.y,建议改为操作santa.rect.x和santa.rect.y,保持Rect对象的一致性,避免潜在的位置同步问题。
内容的提问来源于stack exchange,提问作者Dev Blox
相关产品推荐
相关产品推荐

