pygame 飞机大战碰撞检查的运用(四)精灵、精灵组之间的碰撞检查

目标:精灵和精灵组,精灵组和精灵组之间的碰撞检查。

精灵和精灵组自己的碰撞检查用到一个简单的函数。

spritecollide(sprite, group, dokill, collided=None)

查看sprite.py源代码

def spritecollide(sprite, group, dokill, collided=None):
    """find Sprites in a Group that intersect another Sprite

    pygame.sprite.spritecollide(sprite, group, dokill, collided=None):
        return Sprite_list

    Return a list containing all Sprites in a Group that intersect with another
    Sprite. Intersection is determined by comparing the Sprite.rect attribute
    of each Sprite.

    The dokill argument is a bool. If set to True, all Sprites that collide
    will be removed from the Group.

    The collided argument is a callback function used to calculate if two
    sprites are colliding. it should take two sprites as values, and return a
    bool value indicating if they are colliding. If collided is not passed, all
    sprites must have a "rect" value, which is a rectangle of the sprite area,
    which will be used to calculate the collision.

    """
    if dokill:

        crashed = []
        append = crashed.append

        if collided:
            for s in group.sprites():
                if collided(sprite, s):
                    s.kill()
                    append(s)
        else:
            spritecollide = sprite.rect.colliderect
            for s in group.sprites():
                if spritecollide(s.rect):
                    s.kill()
                    append(s)

        return crashed

    elif collided:
        return [s for s in group if collided(sprite, s)]
    else:
        spritecollide = sprite.rect.colliderect
        return [s for s in group if spritecollide(s.rect)]

sprite 是主动去碰的精灵,group是被碰的精灵,dokill是个bool值,设置成true,被碰的精灵就消失,代码里为 s.kill(),collide是碰撞检查的方式,默认是矩形检查,也可以设置成圆形检查或者图像的mask检查等。

该函数返回的是 一个list属性的,被碰撞的精灵列表。

举个例子,如果要判断英雄飞机是否撞到了敌机,击中就让敌机消失,就用这个函数。因为英雄飞机只有一架,是一个sprite,敌机有很多,可以理解为一个 group。

hero_crash_enemys = pygame.sprite.spritecollide(
            self.hero, self.enemy_sprite, True)

如果不想让敌机死亡,只想减去伤害值,可以用

#撞了也不死,返回一个被撞敌机的列表
hero_crash_enemys = pygame.sprite.spritecollide(
            self.hero, self.enemy_sprite, False)
#列表非空
if hero_crash_enemys:
    for enemy in hero_crash_enemys:
        #每次减少三点生命
        enemy.HP -= 3

这样敌机也不是一碰就死了。可以在敌机的类里添加判断函数,如果生命小于等于零,self.kill() 。自毁。

但飞机大战里最主要的方式不是去撞,而是子弹和飞机的碰撞检查。当然也可以用遍历的方式来写代码,不过sprite里提供了另外一个函数。

def groupcollide(groupa, groupb, dokilla, dokillb, collided=None):

查看源代码:

def groupcollide(groupa, groupb, dokilla, dokillb, collided=None):
    """detect collision between a group and another group

    pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb):
        return dict

    Given two groups, this will find the intersections between all sprites in
    each group. It returns a dictionary of all sprites in the first group that
    collide. The value for each item in the dictionary is a list of the sprites
    in the second group it collides with. The two dokill arguments control if
    the sprites from either group will be automatically removed from all
    groups. Collided is a callback function used to calculate if two sprites
    are colliding. it should take two sprites as values, and return a bool
    value indicating if they are colliding. If collided is not passed, all
    sprites must have a "rect" value, which is a rectangle of the sprite area
    that will be used to calculate the collision.

    """
    crashed = {}
    SC = spritecollide
    if dokilla:
        for s in groupa.sprites():
            c = SC(s, groupb, dokillb, collided)
            if c:
                crashed[s] = c
                s.kill()
    else:
        for s in groupa:
            c = SC(s, groupb, dokillb, collided)
            if c:
                crashed[s] = c
    return crashed

很精炼的几行代码。意思就是 groupa 和 groupb 去碰撞,如果dokilla = True ,groupa 全死,如果 dokillb =Ture,groupb全死。

返回的是一个字典类型 dict,字典的keys()为 groupa里的一个精灵,该键值对应的values()为改精灵撞击到的groupb里的精灵列表。例如,英雄发射了很多子弹,这些子弹有些会击中不同的飞机,有些就飞走了,子弹的伤害值不同,飞机的HP不同。英雄的子弹每颗都是一个sprite,所有子弹存在hero_bullet_sprite里,敌人的飞机每架也是精灵sprite,存在 enemy_sprite里。

现在要达到的目标为,判断子弹是否击中目标,击中了,就把击中的飞机的HP减去击中的子弹伤害值damage。

先要取得击中的子弹和飞机的dict,然后遍历子弹,在根据子弹,取得被该子弹击中的飞机列表,在计算飞机击中后的HP值。

子弹击中飞机,子弹消失掉。(如果是其他类型的游戏,可以都不消失。)在子弹的位置产生爆炸效果,爆炸类Blast也是一个sprite,具有设置位置的函数,爆炸存在self.blast_sprite精灵group里。

 #英雄子弹打飞机
        hero_shot_enemy = pygame.sprite.groupcollide(
            self.hero_bullet_sprite, self.enemy_sprite, True, False)
        if hero_shot_enemy:
            for hero_bullet in hero_shot_enemy:  # in hero_shot_enemy.keys():
                #击中的爆炸效果
                rect = hero_bullet.rect
                blast = Blast(self.scene)
                blast.set_pos(rect.centerx - blast.rect.width // 2,
                              rect.centery - blast.rect.height // 2)
                self.blast_sprite.add(blast)    
                #加分
                self.hero_score += 1
                #当前子弹打中的敌人
                # print(hero_shot_enemy[hero_bullet])
                enemys = hero_shot_enemy[hero_bullet]
                for enemy in enemys:
                    enemy.HP -= hero_bullet.damage
                    print(enemy.HP)

因为涉及到的类比较多,不再贴全部代码,贴一下关于字典里 keys(),values(),itmes()用法的测试代码。假设有herobullet1,和herobullet2两个子弹(炸弹)分别击中了a,b两个列表里的飞机,可以用字典的dice[key] = value来取得对应的list。

a = ['飞机1',"飞机1-1","飞机1-2"]
b = ['飞机2','飞机2-2b','飞机2-1']
crash = {'herobullet1':a,"herobullet2":b}
print('print key')
for key in crash.keys():
      print (key)
print("print value")
for value in crash.values():
      print(value)
print('print items')
for item in crash.items():
      print(item)
print('key to value')
#同 for i in crash.keys():
#keys()可以省略
for i in crash:
      print(i,crash[i])

猜你喜欢

转载自blog.csdn.net/hailler1119/article/details/88825255
今日推荐