Pygame太空射击游戏碰撞检测失效问题求助
太空射击游戏小行星碰撞检测失效问题
我正在开发一款需要躲避并射击小行星的太空射击游戏,调试小行星碰撞检测功能时发现,测试用的单个小行星会直接穿过飞船,完全不触发游戏结束逻辑。试过多种colliderect函数的用法,问题依然存在,相关代码如下:
import pygame pygame.init() #initalizing all the clunky variables size = (900,700) BLACK = (0, 0, 30) RED = (255, 0, 0) YELLOW = (0, 255, 0) x_pos = 450 y_pos = 600 global x_pos global y_pos direct = 0 w, h = 100, 100 screen = pygame.display.set_mode(size) klok = pygame.time.Clock() #main ship image and its rotations ship = pygame.image.load('u-sniper.png') shipL = pygame.transform.rotate(ship, 270) shipR = pygame.transform.rotate(ship, 90) shipD = pygame.transform.rotate(ship, 180) #init hitbox hitbox = ship.get_rect() hitbox.center = w//2,h//2 #funct for drawing ship def drawShip(): if direct == 0: screen.blit(ship, [x_pos,y_pos]) if direct == 1: screen.blit(shipR, [x_pos,y_pos]) if direct == 2: screen.blit(shipD, [x_pos,y_pos]) if direct == 3: screen.blit(shipL, [x_pos,y_pos]) #asteroid obstacles (these are meant to collide with the ship) class asteroid: def __init__(self,x,y,spawn): self.x = x self.y = y self.spawn = spawn def drawA(self): if self.spawn == 1: pygame.draw.circle(screen, RED, (self.x,self.y), 30) def moveA(self): self.y += 8 if self.y > 650: self.spawn = 0 done = False roid = asteroid(450,0,1) #asteroid hitbox init rect_asteroid = (roid.x, roid.y, 30, 30) #here is where its going wrong, collision dosent register def checkForCollisions(): collide = pygame.Rect.colliderect(hitbox,rect_asteroid) if collide == True: done = True #loop while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True screen.fill(BLACK) drawShip() roid.drawA() roid.moveA() #calling fuction, but it dosent work checkForCollisions() #if branch that moves the ship if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: y_pos -= 5 direct = 0 if event.key == pygame.K_DOWN: y_pos += 5 direct = 2 if event.key == pygame.K_RIGHT: x_pos += 5 direct = 3 if event.key == pygame.K_LEFT: x_pos -= 5 direct = 1 #collision between screen boundaries if x_pos > 850: x_pos -= 6 if x_pos < -50: x_pos += 6 if y_pos > 650: y_pos -= 6 if y_pos < 0: y_pos += 6 pygame.display.flip() klok.tick(60) pygame.quit()
问题根源
- 飞船碰撞盒未同步位置:初始化
hitbox后,飞船移动时(修改x_pos/y_pos)未更新hitbox的位置,导致碰撞盒始终停留在初始坐标,完全不跟随飞船实际位置。 - 小行星碰撞盒未实时更新:
rect_asteroid仅在初始化时赋值一次,后续小行星移动(roid.y变化)后,碰撞盒位置未同步更新,永远停留在初始状态。 done变量作用域错误:checkForCollisions函数内直接赋值done = True,但未声明global done,实际修改的是局部变量,无法终止主循环。- 键盘事件处理逻辑错误:按键判断放在事件循环外部,仅会处理最后一个事件,甚至可能出现
event未定义的情况。
修复后的代码
import pygame pygame.init() # 初始化变量 size = (900,700) BLACK = (0, 0, 30) RED = (255, 0, 0) YELLOW = (0, 255, 0) x_pos = 450 y_pos = 600 direct = 0 w, h = 100, 100 screen = pygame.display.set_mode(size) klok = pygame.time.Clock() # 飞船图像及旋转版本 ship = pygame.image.load('u-sniper.png') shipL = pygame.transform.rotate(ship, 270) shipR = pygame.transform.rotate(ship, 90) shipD = pygame.transform.rotate(ship, 180) # 飞船碰撞盒,初始位置与飞船同步 hitbox = ship.get_rect(topleft=(x_pos, y_pos)) # 绘制飞船函数,同步碰撞盒位置 def drawShip(): global hitbox if direct == 0: screen.blit(ship, [x_pos,y_pos]) hitbox = ship.get_rect(topleft=(x_pos, y_pos)) if direct == 1: screen.blit(shipR, [x_pos,y_pos]) hitbox = shipR.get_rect(topleft=(x_pos, y_pos)) if direct == 2: screen.blit(shipD, [x_pos,y_pos]) hitbox = shipD.get_rect(topleft=(x_pos, y_pos)) if direct == 3: screen.blit(shipL, [x_pos,y_pos]) hitbox = shipL.get_rect(topleft=(x_pos, y_pos)) # 小行星类,内置实时碰撞盒 class asteroid: def __init__(self,x,y,spawn): self.x = x self.y = y self.spawn = spawn # 碰撞盒覆盖整个半径30的圆 self.rect = pygame.Rect(self.x - 30, self.y - 30, 60, 60) def drawA(self): if self.spawn == 1: pygame.draw.circle(screen, RED, (self.x,self.y), 30) def moveA(self): if self.spawn == 1: self.y += 8 # 移动时同步碰撞盒中心位置 self.rect.center = (self.x, self.y) if self.y > 650: self.spawn = 0 done = False roid = asteroid(450,0,1) # 碰撞检测函数,修正变量作用域 def checkForCollisions(): global done # 用实时碰撞盒检测,且仅在小行星激活时判断 if roid.spawn == 1 and hitbox.colliderect(roid.rect): done = True # 主循环 while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # 键盘事件移到事件循环内部处理 if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: y_pos -= 5 direct = 0 if event.key == pygame.K_DOWN: y_pos += 5 direct = 2 if event.key == pygame.K_RIGHT: x_pos += 5 direct = 3 if event.key == pygame.K_LEFT: x_pos -= 5 direct = 1 screen.fill(BLACK) drawShip() roid.drawA() roid.moveA() checkForCollisions() # 屏幕边界碰撞处理 if x_pos > 850: x_pos -= 6 if x_pos < -50: x_pos += 6 if y_pos > 650: y_pos -= 6 if y_pos < 0: y_pos += 6 pygame.display.flip() klok.tick(60) pygame.quit()
修复说明
- 同步碰撞盒位置:每次绘制飞船时,根据当前飞船的位置和朝向更新碰撞盒;小行星移动时同步更新自身碰撞盒的中心坐标。
- 修正碰撞盒范围:小行星是半径30的圆,对应的碰撞矩形设为60x60,确保覆盖整个圆形区域,避免碰撞检测遗漏。
- 修复变量作用域:在
checkForCollisions函数中声明global done,确保修改的是全局变量,能正确终止主循环。 - 调整事件处理逻辑:将键盘事件处理移到
for event in pygame.event.get()循环内部,确保所有按键事件都能被正确响应。
内容的提问来源于stack exchange,提问作者user20759990
相关产品推荐
相关产品推荐

