## ストラックアウトの実験記録
### ストラックアウトのゲーム内で使われている放物運動の正確性について調査

- この時の重力は??
- 初速 V_Y=330m/s
- 初速 V_Z=330m/s
- 距離 10m
- 角度 45°
- この場合、重力の値が1万超えます。つまりコードが物理モデルに反している!!
- この時の重力は??
- 初速 V_Y=700m/s
- 初速 V_Z=700m/s
- 距離 10m
- 角度 45°
- 質量 2.12
- この場合、重力の値が1万超えます。つまりコードが物理モデルに反している!!
- 2つともあっているように見えて、実は...物理法則に反しています。
- もう少しC#コードを理論的に見てみましょう。
- C#コードをの方で`rb.AddForce(dir * rb.mass, ForceMode.Impulse);`を追加しました!
その結果...?

- この時の重力は??
- 初速 V_Y=7m/s
- 初速 V_Z=7m/s
- 距離 10m
- 角度 45°
- 質量 2.12
- この条件下で重力9.8になった!質量を変えても同じ動作になった!!👏
- 変更した部分の詳細


- 今回の原因、UnityのC#において初速度が質量に依存していた。その為、全体の物理エンジンにおいて質量の大小で放物運動の到達距離が変化してしまっていた。
---
### 統合したスクリプト
<details>
<summary>
初速度を考慮して統合したスクリプト
</summary>
```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SphereController : MonoBehaviour
{
private Rigidbody rb;
public InputField inputX;
public InputField inputY;
public InputField inputZ;
public Button shootButton;
// *** 追加部分開始 ***
private LineRenderer lineRenderer;
private List<Vector3> positions = new List<Vector3>(); // 軌道の点を記録するリスト
public GameObject spherePrefab; // ボールのプレハブ
private Vector3 initialPosition; // ボールの初期位置
private float screenBoundary = 10f; // 画面外とみなす距離の閾値 // *** 追加部分終了 ***
void Start()
{
rb = GetComponent<Rigidbody>();
// *** 追加部分開始 ***
lineRenderer = GetComponent<LineRenderer>();
// *** 追加部分終了 ***
if (rb == null)
{
Debug.LogError("Rigidbody component is missing from the Sphere object.");
}
else
{
Application.targetFrameRate = 60;
// Rigidbodyを一時的に停止
rb.isKinematic = true;
// 初期位置を保存
initialPosition = transform.position;
// ボタンにリスナーを追加
shootButton.onClick.AddListener(OnShootButtonClicked);
}
}
void OnShootButtonClicked()
{
float x = float.Parse(inputX.text);
float y = float.Parse(inputY.text);
float z = float.Parse(inputZ.text);
Vector3 direction = new Vector3(x, y, z);
// Rigidbodyを再度アクティブにして物理演算を有効化
rb.isKinematic = false;
Shoot(direction);
}
public void Shoot(Vector3 dir)
{
if (rb != null)
{
// 質量に応じた力を適用して、初速度を一定に保つ
rb.AddForce(dir * rb.mass, ForceMode.Impulse);
// *** 追加部分開始 ***
positions.Clear(); // 軌道の記録をクリア
lineRenderer.positionCount = 0; // LineRendererの点の数をリセット
// *** 追加部分終了 ***
}
else
{
Debug.LogError("Rigidbody component is missing from the Sphere object.");
}
}
void Update()
{
// *** 追加部分開始 ***
if (rb != null && rb.velocity.magnitude > 0.01f)
{
positions.Add(transform.position); // 現在位置をリストに追加
lineRenderer.positionCount = positions.Count;
lineRenderer.SetPositions(positions.ToArray());
}
// *** 追加部分終了 ***
// 画面外チェック
if (Mathf.Abs(transform.position.x) > screenBoundary ||
Mathf.Abs(transform.position.y) > screenBoundary ||
Mathf.Abs(transform.position.z) > screenBoundary)
{
Respawn();
}
}
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Cube"))
{
Respawn();
}
}
void Respawn()
{
Debug.Log("Respawn called. Creating new Sphere at position: " + initialPosition);
// 新しいボールを生成
GameObject newBall = Instantiate(spherePrefab, initialPosition, Quaternion.identity);
Debug.Log("New ball created at position: " + newBall.transform.position);
// 現在のボールを削除
Destroy(gameObject);
}
}
```
</details>
<details>
<summary>
変更部分
</summary>
public void Shoot(Vector3 dir)
{
if (rb != null)
{
// 質量に応じた力を適用して、初速度を一定に保つ
rb.AddForce(dir * rb.mass, ForceMode.Impulse);
// *** 追加部分開始 ***
positions.Clear(); // 軌道の記録をクリア
lineRenderer.positionCount = 0; // LineRendererの点の数をリセット
// *** 追加部分終了 ***
}
else
{
Debug.LogError("Rigidbody component is missing from the Sphere object.");
}
}
</details>
## Unity物理エンジンの解説
#### 【調べた情報】

- [引用元](https://shibuya24.info/entry/unity-rigidbody-addforce)
- コメント
- C#コードで初速度を表現するときに、時間を乗算することで初速度の値が時間経過ごとに莫大な数になってしまう。その為、放物運動の瞬間的な力を表現するためにImpulseモードを用いることで初速度を固定値にすることができた。結果、放物運動の最大距離、重力、初速度の関係の方程式が適切に成り立ち、正確な放物運動のモデルを作成することができた。
#### 研究ポスターにも掲載しました。

