当たり判定

スプライトグループを利用して、当たり判定を実装します!

敵クラスの作成

まずは敵のクラスを作成します。

import pygame
from pygame.locals import *
# mathモジュールをインポート
import math

import tools

class Enemy(pygame.sprite.Sprite):
    speed = 5

    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = tools.load_image("data", "haraheris.png", -1)
        self.rect = self.image.get_rect()
        self.rect.center = pos
        self.angle = 90

    def update(self):
        # 円を描きながら移動する
        self.vx = int(3 * math.cos(math.radians(self.angle)))
        self.vy = int(3 * math.sin(math.radians(self.angle)))
        self.rect.move_ip(self.vx, self.vy)
        self.angle += self.speed

    def draw(self, screen):
        screen.blit(self.image, self.rect)

初登場の可愛さ担当キャラクター、「ハラヘリス」ちゃんを敵にします。見るからにハラペコそうで愛くるしいですね。

Playerクラスを参考にしていますが、円を描くように移動するようupdate()内の処理を書き換えています。

円形移動の計算のために標準のmathモジュールを使用するので、忘れずにインポートしておきましょう。

敵クラスファイルを作成したら、Mainクラスでインポートし、インスタンス化します。

ef __init__(self):
    pygame.init()
    pygame.display.set_caption("sample")
    screen = pygame.display.set_mode(SCR_RECT.size)

    # 描画用グループを作成する
    self.all = pygame.sprite.RenderUpdates()
    # 当たり判定用グループを作成する
    self.enemies = pygame.sprite.Group()
    # デフォルトグループに設定する
    player.Player.containers = self.all
    enemy.Enemy.containers = self.all, self.enemies

    # 敵をインスタンス化
    self.enemy_1 = enemy.Enemy((150, 80))
    self.enemy_2 = enemy.Enemy((330, 400))
    # プレイヤーをインスタンス化
    self.player = player.Player((288, 200))

    self.bg = tools.load_image("data", "bg.png")

    clock = pygame.time.Clock()
    while True:
        clock.tick(30)
        self.update()
        self.draw(screen)
        pygame.display.update()
        self.key_handler()

今回は、描画用のグループと当たり判定用のグループを作成します。

RenderUpdates()はGroupの派生クラスで、draw()命令が拡張されているようです(よく分かっていません)。

とりあえず描画用にこちらのクラスを使います。

プレイヤーは一人だけなので、当たり判定用のグループは作成せず、描画用グループのみに所属させます。

これでself.allに対して更新・描画を行えば、プレイヤーと敵すべてが更新・描画されるようになりました。

当たり判定の作成

続いて、当たり判定を作成します。

collision_detection()という関数を新たに定義し、update()内で呼び出すようにします。

def update(self):
    self.all.update()
    self.collision_detection()

def collision_detection(self):
    enemy_collided = pygame.sprite.spritecollide(self.player, self.enemies, False)
    if enemy_collided:
        print("敵と当たっています")

pygame.sprite.spritecollide()は、指定したスプライト(self.player)と接触しているグループ(self.enemies)内のスプライトの一覧を戻り値として返す関数です。

第三引数には、接触したスプライトを削除するかどうかを設定できます。

Trueを設定すると、self.playerと接触した敵のスプライトは削除されます。攻撃のショットなどで設定すれば、貫通弾が作れますね。

enemy_collidedにはself.playerと接触している敵スプライトの一覧が格納されます。

これが空っぽでない=接触しているものがあると判断し、処理を行います。

他にも、グループ同士で接触しているものを探すgroupcollide()や、spritecollide()よりも処理が単純で早いspritecollideany()などがあるので、状況に応じて使い分けることができます。