はじめに
スプラトゥーンのようなアクションゲームでも、実はその動きの裏側には数学がしっかりと活用されています。
本記事では、スプラトゥーンに登場するキャラクターの操作や弾の挙動を例に、ゲーム内の動きがどのような数式で表現され、どのように計算されているのかを、Pythonコードを使って解説します。
参考リンクまとめ
フレームの計算ものせておきます
命中率を考慮したキル速の期待値
Pythonコード
フレーム速度計算とベクトル回転と 弧長と角度の関係
# 日本語と英語のコメント付き / With Japanese and English comments
# === 与えられた値 Given values ===
speed_per_frame = 3.2 # 1フレームあたりの移動距離 / Distance per frame [m/frame]
frame_rate = 50 # フレームレート / Frame rate: frames per second
# === 各時間単位ごとの速度計算 Compute speeds per second, minute, and hour ===
speed_per_second = speed_per_frame * frame_rate # m/s
speed_per_minute = speed_per_second * 60 # m/min
speed_per_hour = speed_per_minute * 60 # m/h
# === プリントで表示 Print the results ===
print("=== 速度の情報 / Speed Information ===")
print(f"1フレームあたりの移動距離 / Distance per frame: {speed_per_frame} m/frame")
print(f"フレームレートの定義 / Frame rate: {frame_rate} frames per second")
print(f"1秒あたりの移動距離 / Speed per second: {speed_per_second:.2f} m/s")
print(f"1分あたりの移動距離 / Speed per minute: {speed_per_minute:.2f} m/min")
print(f"1時間あたりの移動距離 / Speed per hour: {speed_per_hour:.2f} m/h")
import numpy as np
import matplotlib.pyplot as plt
# === パラメータ設定 Parameters ===
distance = 10 # ベクトルの長さ / Vector length [m]
base_angle_deg = 90 # 元の角度(度) / Base angle (degrees)
deviation_angle_deg = 15 # 回転させる角度 / Rotation angle (degrees)
# === ラジアンへの変換 Convert to radians ===
base_angle_rad = np.radians(base_angle_deg)
deviation_angle_rad = np.radians(deviation_angle_deg)
# === ベクトルの定義 Define vectors using complex numbers ===
v0 = distance * np.exp(1j * base_angle_rad) # 元のベクトル Original vector
v1 = v0 * np.exp(1j * deviation_angle_rad) # 回転後のベクトル Rotated vector
# === 座標の差の計算 Compute coordinate differences ===
x_diff = v1.real - v0.real # X座標の差 / Difference in X [m]
y_diff = v1.imag - v0.imag # Y座標の差 / Difference in Y [m]
# === 結果表示 Print results ===
print("=== ベクトルの座標と変化量 / Vector Coordinates and Differences ===")
print(f"Original vector ({base_angle_deg}°): x = {v0.real:.2f} m, y = {v0.imag:.2f} m")
print(f"Rotated vector ({base_angle_deg + deviation_angle_deg}°): x = {v1.real:.2f} m, y = {v1.imag:.2f} m")
print(f"X座標の差 / ΔX: {x_diff:.2f} m")
print(f"Y座標の差 / ΔY: {y_diff:.2f} m")
# === プロット設定 Plot ===
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.grid(True)
margin = 5
ax.set_xlim(-distance - margin, distance + margin)
ax.set_ylim(-distance - margin, distance + margin)
# 円を描画 Draw a reference circle
circle = plt.Circle((0, 0), distance, color='lightblue', fill=False, linestyle='--', label=f'Radius = {distance} m')
ax.add_artist(circle)
# ベクトルの描画 Draw vectors
ax.arrow(0, 0, v0.real, v0.imag, head_width=0.5, head_length=1, fc='blue', ec='blue', label=f'Original ({base_angle_deg}°)')
ax.arrow(0, 0, v1.real, v1.imag, head_width=0.5, head_length=1, fc='red', ec='red', label=f'Rotated (+{deviation_angle_deg}°)')
ax.plot(0, 0, 'ko') # 原点 / Origin
ax.legend()
# タイトルに差を表示 Show differences in title
plt.title(f"Vector Rotation ΔX = {x_diff:.2f} m, ΔY = {y_diff:.2f} m")
plt.xlabel("X [m]")
plt.ylabel("Y [m]")
plt.show()
import numpy as np
import matplotlib.pyplot as plt
# 弧の長さ fixed arc length
arc_length = (5 * np.pi) / 3 # = 5π/3
# 射程 before and after (range)
r_before = 10
r_after = 13
# 角度(度)を求める Calculate angles (degrees)
theta_before = 360 * arc_length / (2 * np.pi * r_before)
theta_after = 360 * arc_length / (2 * np.pi * r_after)
# 各角度を半分にして左右に分ける(扇形描画用) Split into left/right half angles
left_before = -theta_before / 2
right_before = theta_before / 2
left_after = -theta_after / 2
right_after = theta_after / 2
# プロット設定 Plotting
fig, ax = plt.subplots(subplot_kw={'projection': 'polar'})
ax.set_theta_zero_location("N") # 上向きを0度に設定 / Set 0° to top
ax.set_theta_direction(-1) # 時計回り / Clockwise
# 角度をラジアンに変換 Convert to radians
theta1 = np.radians(np.linspace(left_before, right_before, 100))
theta2 = np.radians(np.linspace(left_after, right_after, 100))
# 扇形を描く Draw the sectors
ax.plot(theta1, [r_before]*len(theta1), label=f'Before: {theta_before:.3f}° (r=10 m)', color='red')
ax.plot(theta2, [r_after]*len(theta2), label=f'After: {theta_after:.3f}° (r=13 m)', color='blue')
# 装飾 Styling
ax.set_rmax(15)
ax.set_rticks([5, 10, 13])
ax.set_title("Same Arc Length, Different Range", va='bottom')
ax.legend(loc='lower left')
# 角度差の確認用プリント Print coordinate angles
print("=== Calculation Results ===")
print(f"弧の長さ (Arc Length): {arc_length:.4f} m")
print(f"元の角度 θ1: {theta_before:.4f}°")
print(f"射程13m時の角度 θ2: {theta_after:.4f}°")
print(f"角度差: {theta_before - theta_after:.4f}°")
plt.show()
import numpy as np
import matplotlib.pyplot as plt
# パラメータ設定 / Parameter settings
s = 5 # 最大ブレ角(最大でs度までブレる) / Max possible deviation angle in degrees
b = 0.01 # ブレ値 / Blur coefficient (smaller means more accurate)
# 乱数xとブレ角度yの関係 (式1) / Equation (1): y = s * x^(log_0.5(b))
x = np.linspace(0, 1, 1000)
exponent = np.log(b) / np.log(0.5) # log base 0.5 of b
y = s * x ** exponent # ブレ角度 / Deviation angle in degrees
# 命中率計算 (式2) / Equation (2): x = (y/s)^(log_b(0.5)) = (y/s)**(log(0.5)/log(b))
y_vals = np.linspace(0, s, 1000)
x_cdf = (y_vals / s) ** (np.log(0.5) / np.log(b)) # 累積分布関数 / Cumulative probability
# --- Plot 1: x vs y (Deviation angle for random number) ---
plt.figure(figsize=(10, 5))
plt.plot(x, y, label=f'b = {b}')
plt.xlabel('Random value x (0 to 1)')
plt.ylabel('Deviation angle y [°]')
plt.title('Deviation angle y versus random value x')
plt.grid(True)
plt.legend()
plt.show()
# --- Plot 2: y vs probability (CDF) ---
plt.figure(figsize=(10, 5))
plt.plot(y_vals, x_cdf, label=f'b = {b}')
plt.xlabel('Deviation angle y [°]')
plt.ylabel('Probability that deviation ≤ y')
plt.title('Probability of deviation angle being less than y (Hit rate)')
plt.grid(True)
plt.legend()
plt.show()