エイリアンの反撃
エイリアンがビームを撃つようにします。
ビームクラス
エイリアンが発射するビームを実装します。まずShotクラスを全部コピーしてください。これで9割完成です(笑)プレイヤーが発射する弾とエイリアンが発射するビームはほとんど同じです。弾は上に飛んでいくのに対し、ビームは下に飛んでいくことだけが違います。なのでupdate()を少し変えるだけです。
class Beam(pygame.sprite.Sprite): """エイリアンが発射するビーム""" speed = 5 # 移動速度 def __init__(self, pos): # imageとcontainersはmain()でセット pygame.sprite.Sprite.__init__(self, self.containers) self.rect = self.image.get_rect() self.rect.center = pos def update(self): self.rect.move_ip(0, self.speed) # 下へ移動 if self.rect.bottom > SCR_RECT.height: # 下端に達したら除去 self.kill()
speedはShotより少し遅くしています。ビームは下へ移動するのでmove_ip()でself.speedという正の値を指定します。
エイリアンの攻撃
次にビームを使ってエイリアンが攻撃する処理です。Alienクラスのupdate()に追加します。
class Alien(pygame.sprite.Sprite): """エイリアン""" speed = 2 # 移動速度 animcycle = 18 # アニメーション速度 frame = 0 move_width = 230 # 横方向の移動範囲 prob_beam = 0.005 # ビームを発射する確率 def __init__(self, pos): # imagesとcontainersはmain()でセット pygame.sprite.Sprite.__init__(self, self.containers) self.image = self.images[0] self.rect = self.image.get_rect() self.rect.center = pos self.left = pos[0] # 移動できる左端 self.right = self.left + self.move_width # 移動できる右端 def update(self): # 横方向への移動 self.rect.move_ip(self.speed, 0) if self.rect.center[0] < self.left or self.rect.center[0] > self.right: self.speed = -self.speed # ビームを発射 if random.random() < self.prob_beam: Beam(self.rect.center) # キャラクターアニメーション self.frame += 1 self.image = self.images[self.frame/self.animcycle%2]
prob_beamは、現在のフレームでビームを発射する確率です。この確率が高いとビームが出やすくなります。かなり小さめにしておかないとありえないくらい大量に出ます(笑)Pythonで乱数を扱うのがrandomモジュールです。random.random()で0以上1未満の乱数を返します。この乱数がprob_beamより小さかったらBeamオブジェクトを作ります。引数にはエイリアンの座標を与えます。こうしておくとエイリアンからビームが出たように見えます。Beamクラスはスプライトグループに登録してあるのでオブジェクトを作るだけで描画、更新されます。
プレイヤーとビームの衝突判定
最後にエイリアンの発射したビームとプレイヤーの衝突判定を実装します。この処理はエイリアンとミサイルの衝突判定とほとんど同じです。collision_detection()です。
def collision_detection(player, aliens, shots, beams): """衝突判定""" # エイリアンとミサイルの衝突判定 alien_collided = pygame.sprite.groupcollide(aliens, shots, True, True) for alien in alien_collided.keys(): Alien.kill_sound.play() # プレイヤーとビームの衝突判定 beam_collided = pygame.sprite.spritecollide(player, beams, True) if beam_collided: # プレイヤーと衝突したビームがあれば Player.bomb_sound.play() # TODO: ゲームオーバー処理
エイリアンとミサイルの衝突判定と違って、プレイヤースプライトはただ1つなのでpygame.sprite.groupcollide()ではなく、スプライトとスプライトグループの衝突を調べるpygame.sprite.spritecollide()を使います。
pygame.sprite.spritecollide(sprite, group, dokill)
という形式の関数でspriteとgroup内のいずれかのスプライトが衝突したか調べ、group内の衝突したスプライトをリストで返します。 dokillをTrueにしておくとspriteと衝突したgroup内のスプライトをすべてgroupから消します。groupから消えたスプライトは draw()されなくなるので画面からも消えます。この関数はブロック崩し編でボールとブロックの衝突判定(2008/8/11)にも使いました。上の例では、プレイヤーと衝突したビームがあった場合に爆発音を鳴らしています。ただ、プレイヤーは無敵でまだゲームオーバーにはなりません。