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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 19:25:21