始音kaito 2022-04-13 22:01 采纳率: 40%
浏览 80

pygame飞机大战碰撞检测失灵

问题遇到的现象和发生背景

运行程序时,有时飞机与敌机子弹碰撞会爆炸,有时不会,我无法理解这种问题可能的发生原因

问题相关代码,请勿粘贴截图

import time
import random
import pygame

from pygame.constants import *

#飞机类
class HeroPlane(pygame.sprite.Sprite):
#存放所有子弹的组
bullets=pygame.sprite.Group()
def init(self,screen):
#精灵初始化
pygame.sprite.Sprite.init(self)
#2创建一个图片,玩家飞机
self.player=pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\hero1.png")
#根据图片image获取矩形对象
self.rect=self.player.get_rect()
self.rect.topleft=[0,350]#调用左上角坐标
#飞机速度
self.speed=8
self.screen=screen
#装子弹的列表
self.bullets=pygame.sprite.Group()
#控制按键监听
def key_control(self):

    key_pressed=pygame.key.get_pressed()
    if self.rect.top>0:
        if key_pressed[K_w] or key_pressed[K_UP]:
            self.rect.top-=self.speed
    if self.rect.bottom<731:
        if key_pressed[K_s] or key_pressed[K_DOWN]:
            self.rect.bottom+=self.speed
    if self.rect.left>0:
        if key_pressed[K_a] or key_pressed[K_LEFT]:
           self.rect.left-=self.speed
    if self.rect.right<1300:
        if key_pressed[K_d] or key_pressed[K_RIGHT]:
           self.rect.right+=self.speed
    if Manager.attackspeed==3 and Manager.bulletnumber!=0: 
          if key_pressed[K_SPACE]:
        #按下空格发射子弹
              bullet=Bullet(self.screen,self.rect.right,self.rect.top)
        #把子弹放到列表里
              self.bullets.add(bullet)
        #存放所有飞机子弹的组
              HeroPlane.bullets.add(bullet)
              Manager.bulletnumber-=1
        
        
def update(self):
    self.key_control()
    self.display()
def display(self):
    #将飞机图片贴到窗口中
    self.screen.blit(self.player,self.rect)
    #更新子弹坐标
    self.bullets.update()
    #把所有子弹添加到屏幕
    self.bullets.draw(self.screen)


        

#敌机类
class EnemyPlane(pygame.sprite.Sprite):
#敌方子弹
enemy_bullets=pygame.sprite.Group()
def init(self,screen):
#精灵初始化
pygame.sprite.Sprite.init(self)
#2创建一个图片,玩家飞机
self.player=pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\enemy0.png")
#根据图片image获取矩形对象
self.rect=self.player.get_rect()
y=random.randrange(1,Manager.bg_size[1],50)
self.rect.topleft=[1200,y]#调用左上角坐标
#飞机速度
self.speed=4
self.screen=screen
#装子弹的列表
self.bullets=pygame.sprite.Group()
#敌机移动方向
self.direction='bottom'

def display(self):
    #3将飞机贴到窗口中
    self.screen.blit(self.player,self.rect)
    #更新子弹坐标
    self.bullets.update()
    #把所有子弹添加到屏幕
    self.bullets.draw(self.screen)

def update(self):
    self.auto_move()
    self.auto_fire()
    self.display()
    
def auto_move(self):
    if self.direction=='bottom':
        self.rect.bottom+=self.speed
    elif self.direction=='top':
        self.rect.bottom-=self.speed
    if self.rect.bottom>730:
        self.direction='top'
    elif self.rect.top<0:
        self.direction='bottom'
    self.rect.left-=self.speed-3
def auto_fire(self):
    #自动开火 创建列表对象 添加进列表
    random_num=random.randint(1,15)
    if random_num==8:
        bullet=EnemyBullet(self.screen,self.rect.left,self.rect.top)
        self.bullets.add(bullet)
        #把子弹添加到类属性的子弹组里
        EnemyPlane.enemy_bullets.add(bullet)

#子弹类
#属性
class Bullet(pygame.sprite.Sprite):
def init(self,screen,x,y):
#精灵类初始化
pygame.sprite.Sprite.init(self)
#创建图片
self.image=pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\bullet.png")
#获取矩形对象
self.rect=self.image.get_rect()
self.rect.topleft=[x,y-15]

    #窗口
    self.screen=screen
    #速度
    self.speed=10
def update(self):
    #修改子弹坐标
    self.rect.left+=self.speed
    #如果子弹已出屏幕上方,销毁子弹
    if self.rect.left>1300:
        self.kill()

#敌人子弹类
#属性
class EnemyBullet(pygame.sprite.Sprite):

def __init__(self,screen,x,y):
    #精灵类初始化
    pygame.sprite.Sprite.__init__(self)
    #创建图片
    self.image=pygame.image.load("C:\\Users\\L\\source\\repos\\PythonApplication5\\PythonApplication5\\feijidazhan\\feiji\\bullet1.png")
    #获取矩形对象
    self.rect=self.image.get_rect()
    self.rect.topleft=[x+30-8,y+89-10]
    
    #窗口
    self.screen=screen
    #速度
    self.speed=5
def update(self):
    #修改子弹坐标
    self.rect.left-=self.speed
    #如果子弹已出屏幕上方,销毁子弹
    if self.rect.right<0:
        self.kill()

class GameSound(object):
def init(self):
pygame.mixer.init()
pygame.mixer.music.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\HOYO-MiX - The Fool.flac")
pygame.mixer.music.set_volume(0.5)

def playBackgroundMusic(self):
    pygame.mixer.music.play(-1)

class Bomb(object):
#初始化碰撞
def init(self,screen,type):#type只有我方和敌人
self.screen=screen
if type=="enemy":
#加载爆炸资源
self.mImages=[pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\enemy"+str(v)+".png")for v in range(0,4)]
else:
self.mImages=[pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\hero"+str(v)+".png")for v in range(1,3)]
#设置爆炸播放索引
self.mIndex=0#作为下标,上面导入的图片命名都是从0开始的
#爆炸位置
self.mPos=[0,0]
#爆炸开关
self.mVisible=False

def action(self,rect):
    #触发爆炸方法
    #爆炸的坐标
    self.mPos[0]=rect.left#精灵的位置
    self.mPos[1]=rect.top
    #打开爆炸的开关
    self.mVisible=True

def draw(self):
    if not self.mVisible:
        return
    self.screen.blit(self.mImages[self.mIndex],(self.mPos[0],self.mPos[1]))#贴入名称和位置
    self.mIndex += 1#输入下一张图片直到达到range
    if self.mIndex >=len(self.mImages):#判断是否达到了range设定的最大值,如果达到,传递false
        self.mIndex=0
        self.mVisible=False

class GameBackground(object):
#初始化地图
def init(self,screen):
self.mImage1=pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\background.png")
self.mImage2=pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\background.png")
#窗口
self.screen=screen
#辅助移动地图
self.x1=0
self.x2=Manager.bg_size[0]
#绘制地图
def draw(self):
self.screen.blit(self.mImage1,(self.x1,0))
self.screen.blit(self.mImage2,(self.x2,0))
#移动地图
def move(self):
self.x1-=1
self.x2-=1
if self.x1<=-Manager.bg_size[0]:
self.x1=0
if self.x2<=0:
self.x2=Manager.bg_size[0]
class Manager(object):
bg_size=(1300,731)
#创建敌机定时器的id
create_enemy_id=10
#游戏结束,倒计时的id
game_over_id=11
#游戏是否结束
is_game_over=False
#倒计时时间
over_time=3
#距离月球初始距离
distance=363000
#计算距离月球的id
fly_tomoon_id=39
#攻击速度
attackspeed=8
#攻击速度id
attack_id=15
#弹药
bulletnumber=30
#弹药id
bullet_id=30
#缓时
i=1
def init(self):
pygame.init()
#创建窗口
self.screen=pygame.display.set_mode([1300,731])
#创建背景图片
#self.background=pygame.image.load("C:\Users\L\source\repos\PythonApplication5\PythonApplication5\feijidazhan\feiji\background.png")
self.map=GameBackground(self.screen)
#初始化一个装玩家精灵的group
self.players=pygame.sprite.Group()
#初始化一个装敌机精灵的group
self.enemys=pygame.sprite.Group()
#初始化一个玩家爆炸的对象
self.player_bomb=Bomb(self.screen,'player')
#初始化一个敌机爆炸的对象
self.enemy_bomb=Bomb(self.screen,'enemy')
#初始化一个声音播放的对象
self.sound=GameSound()
def exit(self):
pygame.quit()
exit()
def show_over_text(self):
#游戏结束,显示重新开始倒计时
self.drawText('gameover %d' % Manager.over_time,220,Manager.bg_size[1]/2-50,textHeight=50,fontColor=[255,0,0])
def show_Distance(self):
#在屏幕左上角显示距离月球的距离
self.drawText('DISTANCE TO THE MOON : %d' % Manager.distance,0,0)
def show_bulletnumber(self):
self.drawText('bullet number : %d' % Manager.bulletnumber,1100,700)
def attack_timer(self):
Manager.attackspeed-=1
if Manager.attackspeed==0:
Manager.attackspeed=8
def bullet_timer(self):
if Manager.bulletnumber==0:
if Manager.i!=80:
Manager.i+=1
elif Manager.i==80:
Manager.bulletnumber+=30
Manager.i=1

def distance_timer(self):
    
    Manager.distance-=59
    
def game_over_timer(self):
    self.show_over_text()
    Manager.over_time-=1
    if Manager.over_time==0:
        pygame.time.set_timer(Manager.game_over_id,0)
        Manager.over_time=3
        Manager.is_game_over=False
        self.start_game()
def start_game(self):
    Manager.distance=363000
    Manager.bulletnumber=30
    EnemyPlane.enemy_bullets.remove(EnemyPlane.enemy_bullets)
    manager=Manager()
    manager.main()
 
def new_player(self):
    player=HeroPlane(self.screen)
    self.players.add(player)
def new_enemy(self):
    enemy=EnemyPlane(self.screen)
    self.enemys.add(enemy)

def drawText(self,text,x,y,textHeight=20,fontColor=(0,255,0),backgroundColor=None):
    #通过字体文件获取字体对象
    font_obj=pygame.font.Font("C:\\Users\\L\\source\\repos\\PythonApplication5\\PythonApplication5\\feijidazhan\\feiji\\VINERITC.TTF",textHeight)
    #配置要显示的文字
    text_obj=font_obj.render(text,True,fontColor,backgroundColor)
    #获取要显示的对象的rect
    text_rect=text_obj.get_rect()
    #设置显示对象的坐标
    text_rect.topleft=(x,y)
    #绘制字到指定区域
    self.screen.blit(text_obj,text_rect)
     
def main(self):
    self.sound.playBackgroundMusic()
    #创建一个玩家
    self.new_player()
    #开启创建敌机的定时器
    pygame.time.set_timer(Manager.create_enemy_id,1000)
    self.new_enemy()
    
    while True:
        pygame.time.set_timer(Manager.fly_tomoon_id,1000)
        self.distance_timer()
        pygame.time.set_timer(Manager.attack_id,1000)
        self.attack_timer()
        pygame.time.set_timer(Manager.bullet_id,10000)
        self.bullet_timer()
        #移动地图
        self.map.move()
        #把地图贴在窗口上
        self.map.draw()
        #绘制文字
        self.show_Distance()
        self.show_bulletnumber()
        #self.drawText('DISTANCE TO THE MOON',0,0)#200
        if Manager.is_game_over:
            self.show_over_text()
        
        #遍历所有的事件
        for event in pygame.event.get():
            if event.type==QUIT:
                self.exit()
            elif event.type==Manager.create_enemy_id:
                #创建新的敌机
                self.new_enemy()
            elif event.type==Manager.game_over_id:
                self.game_over_timer()
            

        #调用爆炸的对象
        self.player_bomb.draw()
        self.enemy_bomb.draw()
        
        #玩家飞机和敌机子弹的判断
        if self.players.sprites():
            isover=pygame.sprite.spritecollide(self.players.sprites()[0],EnemyPlane.enemy_bullets,True)
            if isover:
                Manager.is_game_over=True#标志着游戏结束了
                pygame.time.set_timer(Manager.game_over_id,1000)#开始游戏倒计时
                self.player_bomb.action(self.players.sprites()[0].rect)
                #把玩家飞机从精灵组移除
                self.players.remove(self.players.sprites()[0])
                HeroPlane.bullets.remove(HeroPlane.bullets)
        
        #判断碰撞
        iscollide=pygame.sprite.groupcollide(self.players,self.enemys,True,True)#调用group什么玩意判断是否碰撞
        if iscollide:
            Manager.is_game_over=True
            pygame.time.set_timer(Manager.game_over_id,1000)
            items=list(iscollide.items())[0]#转化为列表
            print(items)
            x=items[0]#提取列表
            y=items[1][0]
            #玩家爆炸图片
            self.player_bomb.action(x.rect)#调用bomb输出图片
            #敌机爆炸图片
            self.enemy_bomb.action(y.rect)

        
        #判断子弹和飞机的碰撞
        is_enemy=pygame.sprite.groupcollide(HeroPlane.bullets,self.enemys,True,True)
        if is_enemy:
            items=list(is_enemy.items())[0]
            y=items[1][0]
            #敌机爆炸图片
            self.enemy_bomb.action(y.rect)
            EnemyPlane.enemy_bullets.remove(EnemyPlane.enemy_bullets)
        #玩家飞机和子弹的显示
        self.players.update()
        #敌机和子弹的显示
        self.enemys.update()
        #刷新窗口的内容
        pygame.display.update()
        time.sleep(0.01)

if name=='main':
manager=Manager()
manager.main()

运行结果及报错内容
我的解答思路和尝试过的方法
我想要达到的结果
  • 写回答

1条回答 默认 最新

  • 无聊的木子 2022-04-16 08:00
    关注

    在scratch里,飞机大战要注意子弹碰到飞机的一瞬间就删除了自己,飞机还没来得及判断就没了
    解决办法就是加个等待,但不要太久(0,001秒差不多)

    评论

报告相同问题?

问题事件

  • 创建了问题 4月13日

悬赏问题

  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图
  • ¥15 stm32开发clion时遇到的编译问题