敵を攻撃!

弾を発射して、敵を倒せるようにしてみましょう。

ショットクラスを作成する

shot.pyファイルを新たに作成し、ショットクラスを記述します。

コンストラクタに座標と向きを渡し、画面から出たところで自動的に削除される処理を行います。

アニメーションは、プレイヤーなどと同じような仕組みで実装します。

ラビップルの弾は、かじったリンゴです。

import pygame
from pygame.locals import *

import tools

class Shot(pygame.sprite.Sprite):
    animecycle = 6
    speed = 9

    def __init__(self, pos, direction):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.images = tools.split_image(tools.load_image("data", "shot.png"), 4, 1)
        self.image = self.images[0]
        self.rect = self.image.get_rect()
        self.rect.center = pos
        self.direction = direction
        self.frame = 0

    def update(self):
        if self.direction == 0:
            self.rect.move_ip(self.speed, 0)
            if self.rect.right >= 640 - 32:
                self.kill()
        elif self.direction == 1:
            self.rect.move_ip(-self.speed, 0)
            if self.rect.left <= 0:
                self.kill()
        self.frame += 1
        self.image = self.images[int(self.frame / self.animecycle % 4)]

self.rect.right >= 640 – 32は、「画面幅 – ショットの画像の幅」です。

最終的には「画面外に敵を配置しておき、コースが進むと出てくる」というようなやり方をしたいと考えているので、画面の外までショットが進んでしまい画面外の敵を攻撃しないよう、このような式にしています。

弾を発射する

新たに作成したショットクラスを使えるようにします。

sample.pyでshot.pyをインポートし、コンテナを定義します。

self.shots = pygame.sprite.Group()
shot.Shot.containers = self.all, self.shots

次に、スペースキーを押すと弾が発射されるよう、player.pyに追記します。

リロード時間がないと、無限に弾が発射されてしまうのでリロードの処理も記述しておきます。

# リロード時間を減らす
if self.reload_timer > 0:
    self.reload_timer -= 1
# リロード時間が0なら発射
if pressed_keys[K_SPACE]:
    if self.reload_timer == 0:
        shot.Shot(self.rect.center, self.direction)
        self.reload_timer = self.reload_time

ここまでで、弾を発射することができるようになりました。

あとは敵との当たり判定を設定することで、敵を倒せるようになります。

当たり判定を設定する

このままでは弾が当たっても敵は倒せません。

敵と弾の当たり判定がないからです。

プレイヤーと敵の当たり判定を設定したときと同じ要領で、sample.pyのcollision_detection()に追記していきます。

# 弾と敵との当たり判定
shot_collided = pygame.sprite.groupcollide(self.enemies, self.shots, True, True)

倒した際の効果音やエフェクトもないため、少し味気ないですがこれで弾で敵を倒せるようになりました。

groupcollide()関数は二つのグループで接触しているすべてのスプライトを探す関数です。

第三引数、第四引数はそれぞれ衝突したスプライトをグループから削除するかどうかを指定できます。

どちらもTrueを指定しているので、衝突すると弾も敵も削除されますが、例えば第四引数をFalseにすると弾は削除されず、貫通弾を実装することもできます。