飞机大战(pygame)开发实录七

上一篇讲解敌机、补给包、Boss的生成及控制。本篇就重点讲解碰撞检测原理和实现。


碰撞检测原理

图片在程序中都是矩形,我们看到的不规则形状,只是透明效果。所以碰撞实际就是两个矩形重叠。

碰撞检测原理为矩形重叠
5种重叠

以图中5种重叠为例,重叠部分的矩形坐标都会满足

minX = max(minX1, minX2)
minY = max(minY1, minY2)
maxX = min(maxX1, maxX2)
maxY = min(maxY1, maxY2)

所以只要要判断这个矩形成立,即重叠。


矩形碰撞测试

def CollideTest(postion1, postion2): #碰撞检测
    minX1, minY1,maxX1, maxY1  = postion1
    minX2, minY2,maxX2, maxY2  = postion2
    minX = max(minX1, minX2)
    minY = max(minY1, minY2)
    maxX = min(maxX1, maxX2)
    maxY = min(maxY1, maxY2)
    if (minX < maxX) and (minY < maxY):
        return True
    else:
        return False

有了这个函数,我们只要把需要检测的两个对象的坐标(minX, minY,maxX, maxY )传入函数就可以了。
minX, minY 就是对象的x,y属性,maxX, maxY 可以通过x,y和w,h属性演算获得。

图片坐标获取

然后把对象分成 敌机、敌机子弹、补给包 与 玩家飞机玩家飞机子弹与敌机 两组,进行检测。
这里,玩家飞机做了一个特殊处理。把机头和机身分成1,2两个区域来做碰撞测试,这样3,4区域不会参与碰撞检测。

玩家飞机碰撞检测

碰撞测试

def IsCollide(hero, enemyplanes, Bullets, EnemyBullets, Rewards):
    if hero.live > 0 :
        # 敌机、敌机子弹、补给包 与 玩家飞机的 碰撞检测
        enemyObj = [enemyplanes, EnemyBullets, Rewards]
        for objs in enemyObj:
            for i in range(len(objs) - 1, -1, -1):
                postion1 = (objs[i].x, objs[i].y, objs[i].x + objs[i].w, objs[i].y + objs[i].h)         #(x1,y1,x2,y2)定位矩形区域
                postion2 = (hero.x + hero.w / 3, hero.y, hero.x + hero.w * 2 / 3, hero.y + hero.h / 4)  #机头部分
                postion3 = (hero.x, hero.y + hero.h / 4, hero.x + hero.w, hero.y + hero.h)              # 机身部分
                if CollideTest(postion1, postion2) or CollideTest(postion1, postion3):
                    PlaySound(Sound_Hit)
                    if isinstance(objs[i],EnemyBullet): #当前判断的是敌机子弹,
                        del(objs[i])
                        if hero.invincible == False:
                            hero.hit = True
                    elif isinstance(objs[i],EnemyPlane): #当前判断的是敌机
                        objs[i].hit = True
                        if hero.invincible == False:
                            hero.hit = True
                    elif isinstance(objs[i],RewardGoods): #当前判断的是补给包
                        hero.bulletType = objs[i].RewardItem
                        del(objs[i])

        # 子弹和敌机碰撞检测
        for i in range(len(Bullets) - 1,-1, -1):
            for k in range(len(enemyplanes) -1,-1,-1):
                postion1 = (Bullets[i].x,Bullets[i].y,Bullets[i].x+Bullets[i].w,Bullets[i].y+Bullets[i].h)
                postion2 = (enemyplanes[k].x, enemyplanes[k].y, enemyplanes[k].x + enemyplanes[k].w, enemyplanes[k].y + enemyplanes[k].h)
                if CollideTest(postion1, postion2):
                    del(Bullets[i])
                    enemyplanes[k].hit = True
                    break

带补给包的敌机,被摧毁会刷新补给包。需要先创建补给包的类 RewardGoods

class RewardGoods(Base):
    def __init__(self, pygame_screen, postion, image_name, RewardItem):
        Base.__init__(self, pygame_screen, postion, image_name)
        self.RewardItem = RewardItem
    def move(self):
        self.y += 1
    def display(self):
        self.screen.blit(self.image, (self.x, self.y))

更新Main()

def Main():
    pygame.init()
    scores = 0
    screen = pygame.display.set_mode((480, 852), 0, 32)
    # 添加背景
    Bg = BackGround(screen, Image_Background, 'dynamic')
    bullets = []
    rewards = []
    #添加测试敌机
    enemyBullets = []
    enemyPlanes = []
    enemyPlanes.append(EnemyPlane(screen,enemyBullets))
    enemyPlanes.append(BossPlane(screen,enemyBullets))
    enemyPlanes.append(RewardPlane(screen, enemyBullets,'shotbullet'))
    hero = HeroPlane(screen, bullets)

    while True:
        Bg.display()
        hero.move()  #生成飞机移动后位置
        hero.bulletCoolDown()  # 玩家飞机子弹冷却
        hero.fire()        # 玩家飞机发射子弹
        hero.display()        #绘制玩家飞机
        # 在列表中清除被消灭的敌机
        for i in range(len(enemyPlanes) - 1, -1, -1):
            if enemyPlanes[i].live == 0 and enemyPlanes[i].hit == False:
                if enemyPlanes[i].reward == "shotbullet":  # 敌机如果附带奖励
                    rewards.append(RewardGoods(screen, (enemyPlanes[i].x, enemyPlanes[i].y), Image_Reward2, "shotbullet"))
                elif enemyPlanes[i].reward == "doublebullet":  # 敌机如果附带奖励
                    rewards.append(RewardGoods(screen, (enemyPlanes[i].x, enemyPlanes[i].y), Image_Reward1, "doublebullet"))
                scores += enemyPlanes[i].score
                del (enemyPlanes[i])

        # 更新敌机状态
        for enemy in enemyPlanes:
            enemy.bulletCoolDown()
            enemy.move()
            enemy.fire()
            enemy.display()

        # 刷新奖励补给包
        for Reward in rewards:
            Reward.move()
            Reward.display()
        # IsOverBound(Bullets, EnemyBullets, enemyplanes, Rewards)
        IsOverBound(bullets,enemyBullets,enemyPlanes)
        # 碰撞检测
        IsCollide(hero, enemyPlanes, bullets, enemyBullets, rewards)
        pygame.display.update()
        MainControl(hero, screen)
运行效果

本篇就重点讲解碰撞检测原理和实现,至此游戏主体部分也完成了,下一篇开始逐步完善游戏,首先是增加背景和音效。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容