【Python】自由落下ゲーム開発(スイカゲーム風) Part3
こんにちは、にわこまです!
今回は、ボール同士の衝突判定とサンプルボールを作成します。
本記事で使用するソースコードを以下に示します。
【Python】自由落下ゲーム開発 Part3 ソースコード
何か分からない点がございましたらご連絡お願いいたします!
メールまたはTwitterのDMまで!
スポンサードサーチ
ボール同士の衝突判定の作成
ボール同士の衝突判定では、衝突の検知、コリジョンタイプが同じか判定、衝突したボールを削除、新しいボールを作成の順に処理を実施します。
また、新しいボール作成時にスコアを加算する処理も実施します。
コードの提示
衝突判定のソースコードを以下に示します。
import pygame
import pymunk
import random
# 省略
def collide(arbiter, space, data):
# collided shapes
a, b = arbiter.shapes
# collision type
a_ct = a.collision_type
b_ct = b.collision_type
# 衝突処理を実施しない場合を判定
if(a_ct != b_ct):
# 異なるBall同士の衝突の場合
return
if(a_ct == 11 or b_ct == 11):
# Ball11同士の衝突の場合
return
# 衝突座標を算出
a_x, a_y = a.body.position
b_x, b_y = b.body.position
x = (a_x + b_x) / 2
y = (a_y + b_y) / 2
# 削除するBallを求める
balls_to_remove = []
for ball in data["balls"]:
if(ball.shape == a or ball.shape == b):
balls_to_remove.append(ball)
# Ballを削除する
for ball in balls_to_remove:
space.remove(ball.shape, ball.body)
data["balls"].remove(ball)
# Ballの作成かつスコア更新
if(a_ct == 1 and b_ct == 1):
data["balls"].append(Ball02(x, y))
data["score"] += 1
elif(a_ct == 2 and b_ct == 2):
data["balls"].append(Ball03(x, y))
data["score"] += 3
elif(a_ct == 3 and b_ct == 3):
data["balls"].append(Ball04(x, y))
data["score"] += 6
elif(a_ct == 4 and b_ct == 4):
data["balls"].append(Ball05(x, y))
data["score"] += 10
elif(a_ct == 5 and b_ct == 5):
data["balls"].append(Ball06(x, y))
data["score"] += 15
elif(a_ct == 6 and b_ct == 6):
data["balls"].append(Ball07(x, y))
data["score"] += 21
elif(a_ct == 7 and b_ct == 7):
data["balls"].append(Ball08(x, y))
data["score"] += 28
elif(a_ct == 8 and b_ct == 8):
data["balls"].append(Ball09(x, y))
data["score"] += 36
elif(a_ct == 9 and b_ct == 9):
data["balls"].append(Ball10(x, y))
data["score"] += 45
elif(a_ct == 10 and b_ct == 10):
data["balls"].append(Ball11(x, y))
data["score"] += 55
pass
# 省略
def game():
# Field
tlx, tly = 100, 450
brx, bry = 400, 100
field = Field(tlx, tly, brx, bry)
# Ball
balls = []
# CollisionHandler
handler = space.add_default_collision_handler()
handler.data["balls"] = balls
handler.data["score"] = 0
handler.post_solve = collide
# Game Start
while(True):
# 省略
game()
pygame.quit()
コードの解説
7行目から65行目の「collide関数」は衝突時に実行される処理を定義しています。
9行目では衝突した2つのオブジェクトを取得しています。
11行目と12行目ではそれぞれコリジョンタイプを取得しています。
14行目と16行目では同じコリジョンタイプであるか判定しています。異なるコリジョンタイプである場合はreturnで関数を終了しています。
17行目と19行目では最大ボール同士の衝突か判定しています。最大ボール同士の衝突では新しくボールを作成しませんし、スコアも更新しないためreturnで関数を終了しています。
21行目から24行目では衝突座標を算出しています。新しいボールは算出した座標に表示されます。
26行目から29行目では削除するボールオブジェクトを取得し、削除用ボールリストに追加しています。
31行目から33行目ではボールを削除しています。
32行目では自由落下用の画面オブジェクトから削除しています。
33行目では画面に表示するボールを保持するリストからボールを削除しています。
35行目から65行目では、それぞれ新しいボールの作成とスコアの更新を実施しています。
コリジョンタイプ1同士の場合はBall02を作成し、スコアに1を加算します。
コリジョンタイプ2同士の場合はBall03を作成し、スコアに3を加算します。
以後同じようにボールの作成と、スコアの加算を実施します。
79行目から82行目では衝突時に実行する関数やデータを定義しています。
79行目ではデフォルトの衝突ハンドラーを作成しています。
80行目では関数内で使用するボールデータを定義しています。
81行目では関数内で使用するスコアデータを定義しています。
82行目では衝突後に実行する関数を定義しています。
動作確認
動作確認を実施します。
コードを保存し、コマンドプロンプトを開きます。コードを保存したフォルダまで移動し、以下のコマンドを実行します。
python free_fall_game_part3_1.py
以下のように小麦色の画面にフィールドが表示されることを確認します。
以下のように同じ大きさのボール同士が衝突した際に新しいボールが作成されることを確認します。
スポンサードサーチ
サンプルボールの作成
サンプルボールとは、スイカゲームで言うところの画面右下にある「シンカの輪」のことです。
シンカの輪と同じように円形に11種類のボールを表示します。
サンプルボールはBallクラスではなく新しくCircleクラスを作成し表示します。
コードの提示
サンプルボールのソースコードを以下に示します。
import math
import pygame
import pymunk
import random
# 省略
def convert_cordinates(point):
return point[0], disp_size[1]-point[1]
def rotate_cordinates(point, d):
rad = math.radians(d)
rotated_x = point[0] * math.cos(rad) - point[1] * math.sin(rad)
rotated_y = point[0] * math.sin(rad) + point[1] * math.cos(rad)
return rotated_x, rotated_y
# 省略
class Circle(object):
def __init__(self, x, y, color, radius):
self.x = x
self.y = y
self.color = color
self.radius = radius
def draw(self):
pygame.draw.circle(
display,
self.color,
convert_cordinates((self.x, self.y)),
self.radius
)
def game():
# Field
tlx, tly = 100, 450
brx, bry = 400, 100
field = Field(tlx, tly, brx, bry)
# Ball
balls = []
# CollisionHandler
handler = space.add_default_collision_handler()
handler.data["balls"] = balls
handler.data["score"] = 0
handler.post_solve = collide
# Sample Ball
cx, cy = 600, 200
sample_circles = [
Circle(cx, cy, color_01, radius_01),
Circle(cx, cy, color_02, radius_01),
Circle(cx, cy, color_03, radius_01),
Circle(cx, cy, color_04, radius_01),
Circle(cx, cy, color_05, radius_01),
Circle(cx, cy, color_06, radius_01),
Circle(cx, cy, color_07, radius_01),
Circle(cx, cy, color_08, radius_01),
Circle(cx, cy, color_09, radius_01),
Circle(cx, cy, color_10, radius_01),
Circle(cx, cy, color_11, radius_01),
]
for i, ball in enumerate(sample_circles):
d = -30 + (-30) * i
x, y = rotate_cordinates((0, 100), d)
ball.x += x
ball.y += y
pass
# Game Start
while(True):
for event in pygame.event.get():
if(event.type == pygame.QUIT):
return
if(event.type == pygame.MOUSEBUTTONDOWN):
# 省略
# Fiil background
display.fill(WHEAT)
# Draw Field
field.draw()
# Draw Ball
for ball in balls:
ball.draw()
# Draw Sample Ball
for ball in sample_circles:
ball.draw()
# Display Update
pygame.display.update()
clock.tick(FPS)
space.step(1/FPS)
game()
pygame.quit()
コードの解説
1行目ではmathライブラリをいんぽーとしています。mathライブラリは数学系の計算を使いやすくした関数が含まれるライブラリです。このライブラリの三角関数を用いてサンプルボールの表示位置を計算します。
11行目から15行目の「rotate_cordinates関数」では任意の座標から任意の角度回転したときの座標を算出する関数です。引数は座標を示すpointと角度を示すdです。座標は(x, y)の形式で設定します。
12行目では角度をラジアン単位に変換しています。
13行目ではx座標をd度回転させた座標を算出しています。
14行目ではy座標をd度回転させた座標を算出しています。
15行目では算出した値を返しています。
19行目から31行目のCircleクラスはサンプルボール用のクラスを定義しています。
20行目から24行目の「init関数」は初期処理を実施しています。引数はx座標、y座標、色、半径です。25行目から31行目の「draw関数」はCircleクラスを表示する関数です。
50行目から69行目ではサンプルボールの作成かつ座標更新処理を実施しています。
50行目ではサンプルボール表示位置の中心となる座標を定義しています。
51行目から63行目ではサンプルボールを作成しています。大きさは同じで色は異なるようにしています。また、一旦座標は全て同じにしています。後述する処理で表示位置座標を更新します。
64行目から69行目では表示位置座標を更新しています。
65行目では30度ずつ右回転するように角度を算出しています。
66行目では先述したrotate_cordinates関数を用いて回転後の座標を算出しています。
67行目ではx座標を更新しています。
68行目ではy座標を更新しています。
89行目と90行目ではサンプルボールを表示しています。
動作確認
動作確認を実施します。
コードを保存し、コマンドプロンプトを開きます。コードを保存したフォルダまで移動し、以下のコマンドを実行します。
python free_fall_game_part3_2.py
以下のように画面右下に11種類のボールが表示されていることを確認します。
スポンサードサーチ
まとめ
今回は、同じ大きさのボール同士が衝突した時に実行する関数とサンプルボールの作成を行いました。
次回Part4では、フィールドに落とすボールを保持するCurrentCircleクラスと次ボールを示すNextCircleクラスを作成します。
自由落下ゲーム開発の目次はこちら
本記事で使用したソースコードを以下に示します。
【Python】自由落下ゲーム開発 Part3 ソースコード
最後までお読みいただきありがとうございます。
参考
・pygameの公式ドキュメントはこちら
・pymunkの公式ドキュメントはこちら
・pymunkのチュートリアルを説明しているYoutubeはこちら
・カラーコード 原色大辞典はこちら
・カラーコード 色検索はこちら
スポンサードサーチ