プレイヤーの攻撃
自機から発射したミサイルでエイリアンを倒せるようにします。そのためには、ミサイルとエイリアンが衝突したかを検出する必要があります。Pygameには衝突判定の簡単な方法がたくさんあります。ここではスプライトグループ同士の衝突判定を使います。
グループとグループの衝突判定
前回、実装したようにデフォルトスプライトグループを使っているのでエイリアンたちはaliensグループ、ミサイルはshotsグループに自動的に追加されます。
aliens = pygame.sprite.Group() # エイリアングループ shots = pygame.sprite.Group() # ミサイルグループ # 衝突判定 collision_detection(shots, aliens)
今回は、ミサイルがエイリアンに当たったらエイリアンが消滅するようにしたいのでshotsとaliensの間で衝突判定を行います。もし、 shotsのどれかのミサイルがaliensのどれかのエイリアンに当たったらミサイル、エイリアンともに消滅するようにします。これを簡単にやるためにブロック崩し編のPygameの衝突判定関数(2008/8/11)でちょっと紹介したpygame.sprite.groupcollide()を使います。この関数は2つのグループ間で衝突したスプライトを検出するのに使います。
def collision_detection(shots, aliens): """衝突判定""" # エイリアンとミサイルの衝突判定 alien_collided = pygame.sprite.groupcollide(aliens, shots, True, True) for alien in alien_collided.keys(): Alien.kill_sound.play()
groupcollide()は第1引数と第2引数にそれぞれ衝突判定したいスプライトグループを指定します。第3、第4引数をTrueにすると第 1、第2引数で指定したスプライトグループの中の衝突したスプライトが自動的に消滅します(Falseだと消滅しない)。上の例では、aliensと shotsの間で衝突判定を行い、衝突したAlien、Shotを両方とも消滅するようにしてます。TrueとFalseの組み合わせをいろんなパターンで試してみてください。たとえば、
# 貫通弾(Alienは消滅するがShotは消滅しない) alien_collided = pygame.sprite.groupcollide(aliens, shots, True, False) # 無敵のエイリアン(エイリアンは消滅しないがShotは消滅する alien_collided = pygame.sprite.groupcollide(aliens, shots, False, True)
groupcollide()の戻り値は辞書(ハッシュ)というデータ構造です。
{Shotと衝突したAlien : そのAlienと衝突したShotのリスト}
となります。:の前をキー(key)、:の後をバリュー(value)と呼びます。alien_collidedをprintで表示してみると
{<Alien sprite(in 0 groups)>: [<Shot sprite(in 0 groups)>]}
のようになっています。キーはAlienオブジェクトでバリューはShotオブジェクトのリストになります。(a) 1つのエイリアンに2つのミサイルが同時に当たった場合はバリューリスト内のShotが複数になり、(b) 2つのミサイルが同時に別々のエイリアンに当たった場合はキーが2つ以上になります。例を示します。
(a) { alien1 : [shot1, shot2] } (b) { alien1 : [shot1] , alien2 : [shot2] }
ここで、alien1はAlienオブジェクト、shot1、shot2はShotオブジェクトを表します。ただし、このインベーダーではミサイルの数もエイリアンの数も少ないので同一フレームで上記のような結果になることは滅多にないと思います。groupcollide()に1を指定しているのでぶつかったAlienとShotは特に何もしなくても自動的に消滅します。ここでは、それに加えて消滅したエイリアンごとに断末魔のサウンドを鳴らしています。