Python游戏系列之六_击落敌机
通过前面的代码,我们实现了我方飞机发射子弹,也实现了敌方飞机的随机出现,但实际运行效果是我方子弹和敌方飞机互相穿透,视对方如无物。
因此,现在我们要来解决一个很重要的游戏问题:碰撞检测。
一、碰撞检测
碰撞检测是游戏中非常重要的部分。简单地说,碰撞检测,就是判断两个物体是否发生了碰撞。我方英雄一个大招,是否打中敌人了呢?大招有范围,如果敌人在范围内,就是打中。
为了简化计算,通常把物体简化为矩形或圆形,这样在数学上比较好算。如果物体是不规则的,也可以把它分成几个矩形(或圆形)构成的子物体。
在更精细一些的游戏中,有时会把主角分为头部、胸部、腹部、四肢等部位,因为每个部位受伤对人物的影响不同。
pygame.sprite库中,有一些函数可以用于碰撞检测。参看文档:http://www.pygame.org/docs/ref/sprite.html(从最后往前看)
例如:
pygame.sprite.collide_rect():检测两个精灵是否碰撞,两个精灵视为矩形。
pygame.sprite.collide_circle():检测两个精灵是否碰撞,两个精灵视为圆形。
pygame.sprite.groupcollide():检测两个精灵组是否碰撞,依次判断精灵组A中的每一个精灵是否与精灵组B中的每一个精灵发生碰撞。
groupcollide()这个函数正是我们要的,因为我方子弹有很多,是精灵组,敌方飞机也有很多,也是精灵组。
让我们来认真研究一下这个函数。
函数原型:
groupcollide(group1, group2, dokill1, dokill2, collided = None) -> Sprite_dict
参数:
group1:精灵组1。
group2:精灵组2。
dokill1:发生碰撞时,是否销毁精灵组1中的发生碰撞的精灵。
dokill2:发生碰撞时,是否销毁精灵组2中的发生碰撞的精灵。
collided:自定义的回调函数,你可以自己编写碰撞检测函数。碰撞检测函数的参数是两个精灵,返回值是True/False。
返回值:
返回一个字典,键是精灵组1中发生碰撞的精灵,值是精灵组2中与该精灵发生碰撞的精灵的列表。
二、添加代码
在变量定义部分,添加如下代码:
# 创建被击中的敌方飞机组
enemy_hit_group = pygame.sprite.Group()
在游戏主循环中,添加如下代码:
# 检测我方子弹是否击中敌方飞机
enemy_hit_group.add(pygame.sprite.groupcollide(enemy_group, hero.bullets, True, True))
这样,你就会看到我方子弹击中敌方飞机,然后两者同时消失的场面了。
其实如果只是这样,根本不需要定义enemy_hit_group这个精灵组,直接调用pygame.sprite.groupcollide()函数即可,因为这个函数检测到碰撞时,会销毁发生碰撞的双方物体(因为我们把第3个参数和第4个参数都设成True了呀~~~)。
之所以要定义这个精灵组,主要是想演绎出更震撼的爆炸效果,所以先记住要发生爆炸的敌方飞机,然后在敌方飞机的位置上依次播放爆炸图片,产生爆炸的效果。
三、爆炸效果
1. 首先截取爆炸图片:
代码如下:
enemy_hit_surface = list()
enemy_hit_surface.append(shoot_img.subsurface(pygame.Rect(267, 347, 57, 43)))
enemy_hit_surface.append(shoot_img.subsurface(pygame.Rect(873, 697, 57, 43)))
enemy_hit_surface.append(shoot_img.subsurface(pygame.Rect(267, 296, 57, 43)))
enemy_hit_surface.append(shoot_img.subsurface(pygame.Rect(930, 697, 57, 43)))
2. 在敌方飞机类中添加一个属性(构造方法中):
self.explode_index = 0
3. 在游戏主循环的绘图部分添加如下代码:
# 绘制爆炸效果
for enemy_hit in enemy_hit_group:
screen.blit(enemy_hit_surface[enemy_hit.explode_index], enemy_hit.rect)
if ticks % (ANIMATE_CYCLE // 2) == 0:
if enemy_hit.explode_index < 3:
enemy_hit.explode_index += 1
else:
enemy_hit_group.remove(enemy_hit)
产生爆炸效果的原理是这样的:
将几张图片保存在一个列表中;
通过一个变量从列表中取图片;
需要切换图片时,让此变量递增;
当变量超过范围时,将敌方飞机从爆炸列表中移走。
至此,华丽的爆炸效果就实现啦!