【Python】2D・3D空間における当たり判定の書き方を解説

この記事では、2D空間と3D空間におけるオブジェクト同士の当たり判定方法を解説します。

さらに、Pythonを使用して簡単なサンプルコードを通じて具体的な実装方法を紹介します。

初心者の方でもわかりやすく、ゲーム開発などで役立つ知識を得ることができます。

目次から探す

当たり判定とは

当たり判定とは、ゲーム開発やシミュレーションなどのプログラムで、オブジェクト同士が接触しているかどうかを判定する処理のことを指します。

例えば、キャラクター同士がぶつかったときに反応させたり、弾が敵に当たったときにダメージを与えたりする際に利用されます。

当たり判定は、2D空間だけでなく3D空間でも重要な要素となります。

次のセクションでは、2D空間と3D空間における当たり判定の実装方法について詳しく解説していきます。

2D空間における当たり判定の実装方法

矩形同士の当たり判定

矩形同士の当たり判定を行うには、各矩形の座標やサイズを比較することで衝突を検知します。

以下は簡単なサンプルコードです。

def check_collision(rect1, rect2):
    if (rect1.x < rect2.x + rect2.width and
        rect1.x + rect1.width > rect2.x and
        rect1.y < rect2.y + rect2.height and
        rect1.y + rect1.height > rect2.y):
        return True
    return False

# 矩形の座標とサイズを定義
rect1 = {'x': 0, 'y': 0, 'width': 50, 'height': 50}
rect2 = {'x': 30, 'y': 30, 'width': 40, 'height': 40}

if check_collision(rect1, rect2):
    print("矩形同士が衝突しています")
else:
    print("矩形同士は衝突していません")
衝突判定のサンプル(赤い部分が衝突した箇所)

このサンプルコードでは、2つの矩形が衝突しているかどうかを判定しています。

円同士の当たり判定

円同士の当たり判定は、2つの円の中心座標と半径の距離を比較することで衝突を検知します。

以下は円同士の当たり判定のサンプルコードです。

import math

def check_collision(circle1, circle2):
    distance = math.sqrt((circle1.x - circle2.x)**2 + (circle1.y - circle2.y)**2)
    if distance < circle1.radius + circle2.radius:
        return True
    return False

# 円の中心座標と半径を定義
circle1 = {'x': 0, 'y': 0, 'radius': 30}
circle2 = {'x': 40, 'y': 0, 'radius': 20}

if check_collision(circle1, circle2):
    print("円同士が衝突しています")
else:
    print("円同士は衝突していません")
衝突イメージ

このサンプルコードでは、2つの円が衝突しているかどうかを判定しています。

点と矩形の当たり判定

点と矩形の当たり判定は、点の座標が矩形の範囲内にあるかどうかを判定します。

以下は点と矩形の当たり判定のサンプルコードです。

def check_collision(point, rect):
    if (point.x >= rect.x and point.x <= rect.x + rect.width and
        point.y >= rect.y and point.y <= rect.y + rect.height):
        return True
    return False

# 点の座標を定義
point = {'x': 5, 'y': 5}
# 矩形の座標とサイズを定義
rect = {'x': 0, 'y': 0, 'width': 10, 'height': 10}

if check_collision(point, rect):
    print("点と矩形が衝突しています")
else:
    print("点と矩形は衝突していません")
短径の内側なら衝突とみなされる

このサンプルコードでは、点が矩形内にあるかどうかを判定しています。

点と円の当たり判定

点と円の当たり判定は、点と円の中心座標と半径の距離を比較することで衝突を検知します。

以下は点と円の当たり判定のサンプルコードです。

import math

def check_collision(point, circle):
    distance = math.sqrt((point.x - circle.x)**2 + (point.y - circle.y)**2)
    if distance < circle.radius:
        return True
    return False

# 点の座標を定義
point = {'x': 5, 'y': 5}
# 円の中心座標と半径を定義
circle = {'x': 0, 'y': 0, 'radius': 10}

if check_collision(point, circle):
    print("点と円が衝突しています")
else:
    print("点と円は衝突していません")
円の内側なら衝突とみなされる

このサンプルコードでは、点と円が衝突しているかどうかを判定しています。

3D空間における当たり判定の実装方法

立方体同士の当たり判定

立方体同士の当たり判定を行うためには、各立方体の位置や大きさを考慮して判定する必要があります。

立方体同士が重なっているかどうかを判定するためには、各立方体の中心座標と辺の長さを用いて計算を行います。

以下にサンプルコードを示します。

def check_cube_collision(cube1, cube2):
    # 立方体1の中心座標と辺の長さ
    center1 = cube1['center']
    size1 = cube1['size']
    
    # 立方体2の中心座標と辺の長さ
    center2 = cube2['center']
    size2 = cube2['size']
    
    # 立方体同士が重なっているか判定
    if (abs(center1[0] - center2[0]) * 2 < (size1[0] + size2[0])) and \
       (abs(center1[1] - center2[1]) * 2 < (size1[1] + size2[1])) and \
       (abs(center1[2] - center2[2]) * 2 < (size1[2] + size2[2])):
        return True
    else:
        return False

# 立方体1と立方体2の情報
cube1 = {'center': (0, 0, 0), 'size': (2, 2, 2)}
cube2 = {'center': (1, 1, 1), 'size': (3, 3, 3)}

if check_cube_collision(cube1, cube2):
    print("立方体同士が衝突しています。")
else:
    print("立方体同士は衝突していません。")

球同士の当たり判定

球同士の当たり判定を行うためには、各球の中心座標と半径を考慮して判定します。

球同士が重なっているかどうかは、中心座標間の距離と半径の和を比較することで判定できます。

以下にサンプルコードを示します。

import math

def check_sphere_collision(sphere1, sphere2):
    # 球1の中心座標と半径
    center1 = sphere1['center']
    radius1 = sphere1['radius']
    
    # 球2の中心座標と半径
    center2 = sphere2['center']
    radius2 = sphere2['radius']
    
    # 球同士が重なっているか判定
    distance = math.sqrt((center1[0] - center2[0])**2 + (center1[1] - center2[1])**2 + (center1[2] - center2[2])**2)
    if distance < radius1 + radius2:
        return True
    else:
        return False

# 球1と球2の情報
sphere1 = {'center': (0, 0, 0), 'radius': 2}
sphere2 = {'center': (1, 1, 1), 'radius': 3}

if check_sphere_collision(sphere1, sphere2):
    print("球同士が衝突しています。")
else:
    print("球同士は衝突していません。")

点と立方体の当たり判定

点と立方体の当たり判定を行うためには、点が立方体の内部に含まれるかどうかを判定します。

立方体の各面と点との距離を計算し、その点が立方体内に含まれるかどうかを判定します。

以下にサンプルコードを示します。

def check_point_cube_collision(point, cube):
    # 立方体の中心座標と辺の長さ
    center = cube['center']
    size = cube['size']
    
    # 立方体の各面と点との距離を計算
    distance_x = abs(point[0] - center[0])
    distance_y = abs(point[1] - center[1])
    distance_z = abs(point[2] - center[2])
    
    if distance_x <= size[0] / 2 and distance_y <= size[1] / 2 and distance_z <= size[2] / 2:
        return True
    else:
        return False

# 点と立方体の情報
point = (1, 1, 1)
cube = {'center': (0, 0, 0), 'size': (2, 2, 2)}

if check_point_cube_collision(point, cube):
    print("点は立方体内にあります。")
else:
    print("点は立方体内にありません。")

点と球の当たり判定

点と球の当たり判定を行うためには、点と球の中心座標間の距離と球の半径を比較します。

点が球の表面上にあるかどうかは、中心座標間の距離と半径を比較することで判定できます。

以下にサンプルコードを示します。

import math

def check_point_sphere_collision(point, sphere):
    # 球の中心座標と半径
    center = sphere['center']
    radius = sphere['radius']
    
    # 点と球の中心座標間の距離を計算
    distance = math.sqrt((point[0] - center[0])**2 + (point[1] - center[1])**2 + (point[2] - center[2])**2)
    
    if distance <= radius:
        return True
    else:
        return False

# 点と球の情報
point = (1, 1, 1)
sphere = {'center': (0, 0, 0), 'radius': 2}

if check_point_sphere_collision(point, sphere):
    print("点は球の表面上にあります。")
else:
    print("点は球の表面上にありません。")

Pythonでの当たり判定ライブラリの活用方法

Pygameを用いた2D空間の当たり判定

PygameはPythonでゲームを作成するためのライブラリであり、当たり判定を簡単に実装することができます。

以下に、矩形同士の当たり判定を行うサンプルコードを示します。

import pygame

# Pygameの初期化
pygame.init()

# ウィンドウのサイズ
screen_width = 800
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))

# 矩形の定義
rect1 = pygame.Rect(100, 100, 50, 50)
rect2 = pygame.Rect(200, 200, 50, 50)

# 当たり判定
if rect1.colliderect(rect2):
    print("当たっています!")
else:
    print("当たっていません!")

Pygame 3Dを用いた3D空間の当たり判定

Pygameでは、2Dだけでなく3Dのゲームも作成することができます。

以下に、Pygame 3Dを用いて球同士の当たり判定を行うサンプルコードを示します。

import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *

# Pygameの初期化
pygame.init()
display = (800, 600)
pygame.display.set_mode(display, DOUBLEBUF | OPENGL)

# 球同士の衝突判定を可視化する
def draw_collision_sphere(x, y, z, r):
    glPushMatrix()
    glTranslatef(x, y, z)
    quad = gluNewQuadric()
    gluQuadricDrawStyle(quad, GLU_LINE)
    gluSphere(quad, r, 30, 30)
    gluDeleteQuadric(quad)
    glPopMatrix()

# カメラの初期化
gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)
glTranslatef(0.0, 0.0, -5)

# 球の初期化
ball1 = {'x': 0, 'y': 0, 'z': 0, 'r': 1, 'dx': 0.001, 'dy': 0.001, 'dz': 0.001}
ball2 = {'x': 1, 'y': 1, 'z': 1, 'r': 1, 'dx': -0.001, 'dy': -0.001, 'dz': -0.001}

# メインループ
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()

    # 球の移動
    ball1['x'] += ball1['dx']
    ball1['y'] += ball1['dy']
    ball1['z'] += ball1['dz']
    ball2['x'] += ball2['dx']
    ball2['y'] += ball2['dy']
    ball2['z'] += ball2['dz']

    # 衝突判定
    if (ball1['x'] - ball2['x']) ** 2 + (ball1['y'] - ball2['y']) ** 2 + (ball1['z'] - ball2['z']) ** 2 < (ball1['r'] + ball2['r']) ** 2:
        glColor3f(1, 0, 0)
    else:
        glColor3f(1, 1, 1)

    # 球の描画
    draw_collision_sphere(ball1['x'], ball1['y'], ball1['z'], ball1['r'])
    draw_collision_sphere(ball2['x'], ball2['y'], ball2['z'], ball2['r'])

    # 画面の更新
    pygame.display.flip()
    pygame.time.wait(10)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

これは、Pygameを使用して2Dおよび3D空間での当たり判定を行う方法の一例です。

Pygameを活用することで、簡単にゲーム開発における当たり判定を実装することができます。

終わりに

これで、3D空間における当たり判定の実装方法について解説しました。

立方体同士、球同士、点と立方体、点と球の当たり判定について理解できたかと思います。

それぞれの判定方法を活用して、ゲーム開発などでの衝突判定に役立ててみてください。

目次から探す