前置き
自分は「物理も数学もわからん人」なので分かりやすく記事書けるかなと思って書いてみました。早く完全に理解したいものです。
斜め上にボールを投げたときの実装をしてみたい!
ということで斜方投射を実装してみました。
斜方投射とは物体をある初速度をもって空中に投げ出す動作である。空気抵抗が十分小さく無視できる場合、斜方投射された物体の軌跡は放物線を描く。(Wikipediaより)
斜方投射の物理公式
斜方投射は縦方向、横方向にそれぞれ移動が行われています。そのためXに進んだ距離とYに進んだ距離を求める必要があります。
公式がこちらです。
vx(x方向にt秒後に移動した距離) = v0cosθt
vy(y方向にt秒後に移動した距離) = v0sinθt−(1/2)gt2
※v0は初速度 tは時間 gは重力
この公式をもとに縦横それぞれ出発地点からt秒後にどれ位移動したのか。
を求めてあげればいいのです。
C#で早速書いてみる
それでは公式に沿ってコードを書いてみます。
Mathf.SinとMathf.CosというMathfクラスを使用して実装していきますが、
Mathf.Sin()/Cos()/Tan()はラジアンを使用しているので「度」の形のままで渡しても正しく挙動しません。
補足
ラジアンとは、ざっくりいうと
角度を ° とは別の単位であらわしたものだよ
度からラジアンに変換する定数のMathf.Deg2Rad
が、Mathfクラスには用意されています。
(度数にMathf.Deg2Radを掛ければラジアンになる)
以下が、公式をコードに落とし込んだときのものです。
float vx = Mathf.Cos(Mathf.Deg2Rad * degree) * v0 * time;
float vy = (Mathf.Sin(Mathf.Deg2Rad * degree) * v0) * time - (1 / 2) * gravity * Mathf.Pow(time, 2);
完成図
移動距離の求め方が分かったので、毎フレームごとに移動距離をもとめてボールをその位置に移動させます。
以下が実装したときのコードです。
float gravity = 9.8f; // 重力
[SerializeField] private float degree = 30f; // 角度
[SerializeField] private float v0 = 10; // 初速度
private IEnumerator ProjectileMotion(Transform ballTransform)
{
// 経過時間
float time = 0;
// 開始位置
Vector3 startPos = ballTransform.position;
while (true)
{
time += Time.deltaTime;
float vx = Mathf.Cos(Mathf.Deg2Rad * degree) * v0 * time;
float vy = (Mathf.Sin(Mathf.Deg2Rad * degree) * v0) * time - (1 / 2) * gravity * Mathf.Pow(time, 2);
// ボールの位置を移動。(画面左方向に投げたいのでXは移動距離を引いている)
ballTransform.position = new Vector3(startPos.x - vx, startPos.y + vy, ballTransform.position.z);
// y方向への移動がなくなったら終了。
if (vy <= 0)
{
// ボールのy座標は0にして調整
ballTransform.position = new Vector3(ballTransform.position.x, 0, ballTransform.position.z);
yield break;
}
yield return null;
}
}
完成系はこちら。
ボールをセットしたあとに斜方投射しています。
最後に
物理と数学を調べながらやってると学生時代のわずかな記憶が呼び覚まされかけた気がしました。
調べて→実際に動かすのは面白いですね
この後は、応用として決められた秒数・着地位置・角度から逆算してスピードの調整をしていこうと思います。