【Pygame】スプライト同士の衝突判定と跳ね返りを実装する方法

Pygameでスプライト同士の衝突判定と跳ね返りを実装する方法をソースコード付きで詳しく解説します。

スプライト同士の衝突判定と跳ね返り

Pygameでは、self.rect.colliderect を使ってスプライト同士の衝突判定と跳ね返りを実装できます。
self.rect.colliderect(other_rect) は、2つの矩形(Rect オブジェクト)が衝突しているかどうかを判定するメソッドです。
衝突している場合は True を返し、そうでない場合は False を返します。

サンプルコード

5つの画像オブジェクトが衝突したら跳ね返るサンプルコードです。


コード解説

上記コードの各部分について解説します。

1. インポートと初期設定

import sys
import pygame
from pygame.locals import *
  • sys モジュールは、システム固有のパラメータや関数にアクセスするために使用します。
  • pygame は、ゲーム開発のためのライブラリです。
  • pygame.locals から * をインポートすることで、Pygame の定数を直接使用できます。

2. 画面サイズの設定

SCREEN = Rect(0, 0, 600, 400)   # 画面サイズ
  • SCREEN は、ゲームウィンドウのサイズを設定するための Rect オブジェクトです。

3. 画像ファイルパスの設定

GIRL1_IMG_PATH = "/Users/github/sample/python/pygame/sprite/girl1.png"
GIRL2_IMG_PATH = "/Users/github/sample/python/pygame/sprite/girl2.png"
GIRL3_IMG_PATH = "/Users/github/sample/python/pygame/sprite/girl3.png"
GIRL4_IMG_PATH = "/Users/github/sample/python/pygame/sprite/girl4.png"
GIRL5_IMG_PATH = "/Users/github/sample/python/pygame/sprite/girl5.png"
  • 各スプライトの画像ファイルのパスを設定します。

4. スプライトのクラス定義

class Girl(pygame.sprite.Sprite):
    def __init__(self, filepath, pos, vxy, angle=0):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = pygame.image.load(filepath).convert_alpha()
        if angle != 0:
            self.image = pygame.transform.rotate(self.image, angle)
        x, y = pos
        vx, vy = vxy
        w = self.image.get_width()
        h = self.image.get_height()
        self.rect = Rect(x, y, w, h)
        self.vx = vx
        self.vy = vy
        self.angle = angle
  • Girl クラスは、pygame.sprite.Sprite を継承しています。
  • __init__ メソッドでは、画像の読み込み、位置と速度の設定、回転角度の適用を行います。

5. スプライトの更新メソッド

def update(self):
    self.rect.move_ip(self.vx, self.vy)
    if self.rect.left < 0 or self.rect.right > SCREEN.width:
        self.vx = -self.vx
    if self.rect.top < 0 or self.rect.bottom > SCREEN.height:
        self.vy = -self.vy
    self.rect = self.rect.clamp(SCREEN)

    for sprite in self.containers:
        if sprite != self and self.rect.colliderect(sprite.rect):
            self.vx = -self.vx
            self.vy = -self.vy
  • update メソッドでは、スプライトの位置を更新し、画面の端に達した場合や他のスプライトと衝突した場合に速度を反転させます。つまり、スプライトは画面の端や他のスプライトに衝突すると跳ね返る動きをします。
  • self.rect.move_ip(self.vx, self.vy):スプライトの位置を現在の速度(vx, vy)に基づいて更新します。
  • if self.rect.left < 0 or self.rect.right > SCREEN.width:
    • スプライトが画面の左端または右端に達した場合、vxの符号を反転させて反射させます。
  • if self.rect.top < 0 or self.rect.bottom > SCREEN.height:
    • スプライトが画面の上端または下端に達した場合、vyの符号を反転させて反射させます。
  • self.rect = self.rect.clamp(SCREEN):
    • スプライトの位置を画面内に制限します。
  • 他のスプライトとの衝突処理:
    • for sprite in self.containers:で同じコンテナ内の他のスプライトをループします。つまり、 self.containers 内の他のスプライトをループし、自分自身以外のスプライトと衝突しているかを self.rect.colliderect(sprite.rect) で判定します。
    • if sprite != self and self.rect.colliderect(sprite.rect):自分自身以外のスプライトと衝突した場合、vxvyの符号を反転させて反射させます。

6. スプライトの描画メソッド

def draw(self, screen):
    screen.blit(self.image, self.rect)
  • draw メソッドでは、スプライトを画面に描画します。

7. メイン関数

def main():
    pygame.init()
    screen = pygame.display.set_mode(SCREEN.size)
    girl_group = pygame.sprite.RenderUpdates()
    Girl.containers = girl_group

    girl1 = Girl(GIRL1_IMG_PATH, (300, 200), (2, 0), 0)
    girl2 = Girl(GIRL2_IMG_PATH, (200, 200), (0, 2), -20)
    girl3 = Girl(GIRL3_IMG_PATH, (100, 200), (2, 3), 0)
    girl4 = Girl(GIRL4_IMG_PATH, (200, 100), (1, 2), 20)
    girl5 = Girl(GIRL5_IMG_PATH, (300, 300), (2, 1), 0)

    clock = pygame.time.Clock()
    running = True

    while running:
        clock.tick(30)
        screen.fill((0, 60, 0))
        girl_group.update()
        dirty_rects = girl_group.draw(screen)
        pygame.display.update(dirty_rects)

        for event in pygame.event.get():
            if event.type == QUIT:
                running = False
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    running = False

    pygame.quit()
    sys.exit()
  • main 関数では、Pygame の初期化、画面の設定、スプライトグループの作成、スプライトのインスタンス化、メインループの実行を行います。
  • メインループでは、画面の更新、スプライトの更新、イベントの処理を行います。

8. エントリーポイント

if __name__ == "__main__":
    main()
  • この部分は、スクリプトが直接実行された場合に main 関数を呼び出します。

関連ページ

Pygameの使い方については以下ページで解説しています。

【Pygame超入門】使い方とサンプルゲームを解説
Pythonモジュール「Pygame」で2Dゲームを簡単に制作する方法を入門者向けに解説します。

Python全般については以下ページで解説しています。

【Python超入門】使い方とサンプル集
Pythonの基礎文法から応用例まで入門者向けに解説します。

コメント