Pygame入門 — 当たり判定の基礎

概要

当たり判定はゲームのコア要素の一つです。
ここでは矩形(rect)判定、円やマスクによる精密判定、複数判定の効率的な処理方法を説明します。
用途に応じた手法を選ぶことが重要です。

矩形(Rect)ベースの当たり判定

最も簡単で高速なのが矩形(Rect)同士の衝突判定です。
スプライトが矩形領域を持っている場合、pygame.Rect.colliderect() を使って衝突を検出します。
多くのケースで十分に機能し、パフォーマンスも良好です。

# rect ベースの判定
if sprite1.rect.colliderect(sprite2.rect):
    handle_collision(sprite1, sprite2)

 

マスク(ピクセル単位)の判定

画像の透明部分を考慮した精密な当たり判定は pygame.mask を使います。
マスクはピクセル単位の衝突を検出できますが、計算コストが高くなるため必要な場合に限定して使います。
オフセット計算に注意してください。

# mask を使った判定の例
mask1 = pygame.mask.from_surface(sprite1.image)
mask2 = pygame.mask.from_surface(sprite2.image)
offset = (sprite2.rect.left - sprite1.rect.left, sprite2.rect.top - sprite1.rect.top)
if mask1.overlap(mask2, offset):
    handle_precise_collision(sprite1, sprite2)

 

円や距離ベースの判定

キャラクターや弾丸などを中心点と半径で扱う場合は、距離の比較で判定できます。
平方根を使う計算は重いので、距離の二乗を比較する手法が一般的です。

# 円判定(距離の二乗を利用)
dx = x1 - x2
dy = y1 - y2
r = r1 + r2
if dx*dx + dy*dy <= r*r:
    handle_collision()

 

多対多の衝突検出(最適化)

エネミー数や弾数が多い場合、全探索は O(n^2) になり負荷が高くなります。
空間分割(グリッド、クアッドツリー)やバウンディングボリューム階層(BVH)を使って候補を絞ると効率的です。
Pygame では近接判定用に簡易なグリッドを実装するのが現実的です。

スプライトグループでの衝突検出支援

pygame.sprite にはグループ間の当たり判定を支援する関数があります。
groupcollide や spritecollide を活用すると簡潔に実装できます。以下は使用例です。

# groupcollide の例(rect ベース)
collisions = pygame.sprite.groupcollide(bullets, enemies, True, True)

# spritecollide(マスク使用例)
hits = pygame.sprite.spritecollide(player, enemies, False, pygame.sprite.collide_mask)

 

反発・ダメージ・衝突解決の考え方

衝突検出だけでなく、衝突解決(反発、位置補正、ダメージ処理など)も重要です。
物理演算を導入する場合は独自に運動方程式を扱うか、外部の物理エンジンを併用することを検討します。
単純なゲームでは位置補正や速度反転などで十分なケースが多いです。

手法 用途と特徴
Rect.colliderect 高速・簡易。矩形領域で十分な場合に有効。
Mask.overlap ピクセル単位の精密判定。コスト高。
距離(円)判定 球状オブジェクトの近接検出に有効。軽量。