Pygame Sprite子弹未触鸟却消失问题排查及命中检测实现
问题排查:Pygame鸟类狩猎游戏中子弹未触碰鸟类却消失的问题
我用Pygame Sprite开发了一款狩猎鸟类的游戏,包含Birds、HunterGun、Bullet三类精灵。需求是子弹击中鸟类后,两者立即消失。但现在遇到问题:朝鸟类方向开枪时,鸟类会在子弹还没碰到的时候就消失了,帮忙排查代码问题。
原代码
import pygame import os import random BACKGROUND_IMAGE = pygame.image.load( os.path.join("Assets", "2dforest.jpeg")) BACKGROUND_WIDTH, BACKGROUND_HEIGHT = 900, 500 pygame.display.set_caption("Hunting Birds") WIN = pygame.display.set_mode((BACKGROUND_WIDTH, BACKGROUND_HEIGHT)) COLOR = (255, 200, 98) class Birds(pygame.sprite.Sprite): def __init__(self, image, width, height, pos_x, pos_y): super().__init__() self.width = width self.height = height self.pos_x = pos_x self.pos_y = pos_y self.image = pygame.image.load( os.path.join("Assets", image)).convert_alpha() self.image = pygame.transform.scale(self.image, (175, 175)) self.rect = self.image.get_rect() self.rect.center = (self.pos_x, self.pos_y) class HunterGun(pygame.sprite.Sprite): def __init__(self, image, width, height, pos_x, pos_y): super().__init__() self.width = width self.height = height self.pos_x = pos_x self.pos_y = pos_y self.image = pygame.image.load( os.path.join("Assets", image)).convert_alpha() self.image = pygame.transform.scale(self.image, (175, 175)) self.rect = self.image.get_rect() self.rect.center = (self.pos_x, self.pos_y) def move_and_turn(self, mover): keys_pressed = pygame.key.get_pressed() if (keys_pressed[pygame.K_LEFT]): pos_x, pos_y = self.rect.center pos_x -= mover self.rect.center = (pos_x, pos_y) elif (keys_pressed[pygame.K_RIGHT]): pos_x, pos_y = self.rect.center pos_x += mover self.rect.center = (pos_x, pos_y) elif (keys_pressed[pygame.K_UP]): pos_x, pos_y = self.rect.center pos_y -= mover self.rect.center = (pos_x, pos_y) elif (keys_pressed[pygame.K_DOWN]): pos_x, pos_y = self.rect.center pos_y += mover self.rect.center = (pos_x, pos_y) print(self.rect, "Down") def rotate(self, angle): self.angle = angle self.image = pygame.transform.rotate( self.image, self.angle) self.pos_y += 2 self.pos_x -= 18 print(self.pos_x) self.rect.center = (self.pos_x, self.pos_y) self.rect = self.image.get_rect(center=(self.rect.center)) def create_bullect(self): pos_x, pos_y = self.rect.center return Bullet(pos_x + 95, pos_y - 67) class Bullet(pygame.sprite.Sprite): def __init__(self, pos_x, pos_y): super().__init__() self.pos_x = pos_x self.pos_y = pos_y self.image = pygame.image.load( os.path.join("Assets", "bullet.png")).convert_alpha() self.image = pygame.transform.scale(self.image, (50, 80)) self.rect = self.image.get_rect(center=(pos_x, pos_y)) def update(self): self.rect.x += 13 self.pos_x if(self.rect.x >= BACKGROUND_WIDTH + 200): print(self.rect) self.kill() elif(self.rect.y >= BACKGROUND_HEIGHT + 200): self.kill() birds_sprite = pygame.sprite.Group() for target in range(10): new_target = Birds("birds.png", 100, 100, random.randrange(0, BACKGROUND_WIDTH), random.randrange(0, BACKGROUND_HEIGHT)) birds_sprite.add(new_target) gunhunter = HunterGun("gunner.png", 100, 100, BACKGROUND_WIDTH // 2, BACKGROUND_HEIGHT//2) gun_sprite = pygame.sprite.Group() gun_sprite.add(gunhunter) bullet_group = pygame.sprite.Group() pygame.init() clock = pygame.time.Clock() run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False keys_pressed = pygame.key.get_pressed() if (keys_pressed[pygame.K_k]): bullet_group.add(gunhunter.create_bullect()) pygame.sprite.spritecollideany( birds_sprite, bullet_group, True, True) if(keys_pressed[pygame.K_r]): gunhunter.rotate(3) picture = pygame.transform.scale(BACKGROUND_IMAGE, (1000, 540)) pygame.display.flip() WIN.blit(picture, (0, 0)) birds_sprite.draw(WIN) bullet_group.draw(WIN) gun_sprite.draw(WIN) gunhunter.move_and_turn(4) birds_sprite.update() gun_sprite.update() bullet_group.update() clock.tick(60) pygame.quit()
核心问题与修复方案
1. 碰撞检测逻辑错误
- 问题点:你在按下开枪键的瞬间就调用了
spritecollideany,此时子弹刚生成还没移动,就直接触发碰撞删除;而且参数顺序搞反了,spritecollideany第一个参数应该是单个精灵,第二个是精灵组,你把鸟类组和子弹组传反了,导致检测逻辑完全错误。 - 修复:把碰撞检测移到主循环的更新阶段,在子弹移动后再检测,改用
groupcollide直接检测两组精灵的碰撞,参数顺序为子弹组在前、鸟类组在后,设置True, True删除碰撞双方。
2. 画面绘制顺序错误
- 问题点:先调用
pygame.display.flip()再绘制背景和精灵,导致显示的是上一帧内容,当前帧的绘制无法及时呈现,也会干扰你对碰撞时机的判断。 - 修复:先绘制背景、所有精灵,最后调用
pygame.display.flip()更新画面。
3. 枪支旋转逻辑缺陷
- 问题点:直接修改原始图像进行旋转,多次旋转会导致图像变形;手动调整
pos_x/pos_y的方式不严谨,容易导致精灵位置偏移。 - 修复:保存原始图像,每次旋转都基于原始图操作;旋转后用rect的中心重新定位,不再手动调整坐标。
4. 按键事件重复触发
- 问题点:用
key.get_pressed()处理开枪和旋转,按住按键时会重复触发操作,导致一次按键生成多个子弹或多次旋转。 - 修复:改用
KEYDOWN事件处理,确保一次按键只触发一次操作。
修复后的完整代码
import pygame import os import random BACKGROUND_IMAGE = pygame.image.load(os.path.join("Assets", "2dforest.jpeg")) BACKGROUND_WIDTH, BACKGROUND_HEIGHT = 900, 500 pygame.display.set_caption("Hunting Birds") WIN = pygame.display.set_mode((BACKGROUND_WIDTH, BACKGROUND_HEIGHT)) COLOR = (255, 200, 98) class Birds(pygame.sprite.Sprite): def __init__(self, image, width, height, pos_x, pos_y): super().__init__() self.image = pygame.image.load(os.path.join("Assets", image)).convert_alpha() self.image = pygame.transform.scale(self.image, (175, 175)) self.rect = self.image.get_rect(center=(pos_x, pos_y)) class HunterGun(pygame.sprite.Sprite): def __init__(self, image, width, height, pos_x, pos_y): super().__init__() self.original_image = pygame.image.load(os.path.join("Assets", image)).convert_alpha() self.original_image = pygame.transform.scale(self.original_image, (175, 175)) self.image = self.original_image.copy() self.rect = self.image.get_rect(center=(pos_x, pos_y)) self.angle = 0 def move_and_turn(self, mover): keys_pressed = pygame.key.get_pressed() pos_x, pos_y = self.rect.center if keys_pressed[pygame.K_LEFT]: pos_x -= mover elif keys_pressed[pygame.K_RIGHT]: pos_x += mover elif keys_pressed[pygame.K_UP]: pos_y -= mover elif keys_pressed[pygame.K_DOWN]: pos_y += mover self.rect.center = (pos_x, pos_y) def rotate(self, angle): self.angle += angle self.image = pygame.transform.rotate(self.original_image, self.angle) self.rect = self.image.get_rect(center=self.rect.center) def create_bullect(self): pos_x, pos_y = self.rect.center return Bullet(pos_x + 95, pos_y - 67) class Bullet(pygame.sprite.Sprite): def __init__(self, pos_x, pos_y): super().__init__() self.image = pygame.image.load(os.path.join("Assets", "bullet.png")).convert_alpha() self.image = pygame.transform.scale(self.image, (50, 80)) self.rect = self.image.get_rect(center=(pos_x, pos_y)) def update(self): self.rect.x += 13 if self.rect.x >= BACKGROUND_WIDTH + 200 or self.rect.y >= BACKGROUND_HEIGHT + 200: self.kill() birds_sprite = pygame.sprite.Group() for target in range(10): new_target = Birds("birds.png", 100, 100, random.randrange(0, BACKGROUND_WIDTH), random.randrange(0, BACKGROUND_HEIGHT)) birds_sprite.add(new_target) gunhunter = HunterGun("gunner.png", 100, 100, BACKGROUND_WIDTH // 2, BACKGROUND_HEIGHT//2) gun_sprite = pygame.sprite.Group() gun_sprite.add(gunhunter) bullet_group = pygame.sprite.Group() pygame.init() clock = pygame.time.Clock() run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_k: bullet_group.add(gunhunter.create_bullect()) if event.key == pygame.K_r: gunhunter.rotate(3) # 绘制背景和精灵 picture = pygame.transform.scale(BACKGROUND_IMAGE, (BACKGROUND_WIDTH, BACKGROUND_HEIGHT)) WIN.blit(picture, (0, 0)) birds_sprite.draw(WIN) bullet_group.draw(WIN) gun_sprite.draw(WIN) # 更新所有精灵状态 gunhunter.move_and_turn(4) birds_sprite.update() gun_sprite.update() bullet_group.update() # 检测子弹与鸟类的碰撞 pygame.sprite.groupcollide(bullet_group, birds_sprite, True, True) pygame.display.flip() clock.tick(60) pygame.quit()
内容的提问来源于stack exchange,提问作者Chukwuma Kingsley
相关产品推荐
相关产品推荐

