rigidbodyの軌道予測線を作成してみた(空気抵抗なし)
空気抵抗がない場合のrigidbodyの軌道予測線を作成しました。放物線運動の公式によって作成した起動予測線はrigidbodyの軌道と一致していなかったため、新たに式を導出しrigidbodyの軌道と一致するかを確認しました。
※空気抵抗を考慮した起動予測線はこちら
放物線運動の公式をもとに作成
放物線運動の公式
原点から初速\(v_{0}\)で発射された物体の時刻\(t\)における位置\(x\),\(y\)は
$$ \begin{align} &x=v_{0}tcos\theta\\ &y=v_{0}tsin\theta-\frac{1}{2}gt^{2} \end{align} $$と表せます。ここで\(g\)は重力加速度です。この式とLineRendererを使用して軌道予測線を作成しました。
Script
放物線運動の公式を使用した軌道予測線を描画するためのScriptは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DrawLine : MonoBehaviour { public GameObject preLineRenderer; public GameObject preBullet; private GameObject objLineRenderer; private LineRenderer lineRenderer; private int count = 0; private float mass = 1f, drag = 1f, x = 0f, y = 0f, initVel = 10f, angle = 0f, step = 0.05f, time = 0; private float gravity = 9.80665f; private Vector3 vel; // Use this for initialization void Start () { angle = 30f * Mathf.Deg2Rad; vel = new Vector3(initVel * Mathf.Cos(angle), initVel * Mathf.Sin(angle), 0); objLineRenderer = Instantiate(preLineRenderer, gameObject.transform); objLineRenderer.transform.localPosition = Vector3.zero; lineRenderer = objLineRenderer.GetComponent<LineRenderer>(); Time.timeScale = 0.2f; } void ZeroDrag() { if (y >= 0) { x = vel.x * time; y = vel.y * time - 0.5f * gravity * time * time; lineRenderer.positionCount = count + 1; lineRenderer.SetPosition(count, new Vector3(x, y, 0)); count++; time += step; } } // Update is called once per frame void Update () { ZeroDrag(); } } |
実行結果
作成した軌道予測線が実際の挙動とあっているか否かを確認しました。結果は以下の通りです。この結果より、投射されたオブジェクトが軌道予測線から徐々にずれていくことがわかりました。
Unity
公式を使用して作成した軌道予測線は、ずれが生じていることが分かりました。そこで、Unityでは速度を\(dt\)(Time.fixedDeltaTime)秒前の速度をもとに計算しているのであろうと仮定し、位置\(x\),\(y\)を求めました。
式の修正
・位置 \(x\) の導出
時間の刻み幅を\(dt\)とすると、\(x\)方向の速度\(v_{x}\)は
$$ \begin{align} &v_{x}(0)=v_{0x}\\ &v_{x}(dt)=v_{0x}\\ &v_{x}(2dt)=v_{0x}\\ \end{align} $$以上の式より
$$ v_{x}(kdt)=v_{0x} $$となります。よって、\(dt\)秒の間に移動する距離\(dx\)は
$$ dx=v_{x}(kdt)dt=v_{0x}dt $$と表せます。これより、位置\(x\)は
$$ \begin{align} x&=\sum_{k=1}^{n}v_{0x}dt\\ &=v_{0x}ndt \end{align} $$となります。ここで、\(n=\frac{t}{dt}\)とすると
$$ x=v_{0x}t\\ $$となり、\(t\)秒後の位置\(x\)は上式で表せることがわかります。
・位置 \(y\) の導出
\(y\)方向の速度\(v_{y}\)は
$$ v_{y}=v_{0y}-gt $$と表せます。時間の刻み幅を\(dt\)とすると、\(y\)方向の速度\(v_{y}\)は
$$ \begin{align} &v_{y}(0)=v_{0y}\\ &v_{y}(dt)=v_{0y}-gdt\\ &v_{y}(2dt)=v_{y}(dt)-gdt=v_{0y}-2gdt \end{align} $$となります。以上の式より
$$ v_{y}(kdt)=v_{0y}-gdtk $$となります。よって、\(dt\)秒間に\(y\)方向へ移動する距離\(dy\)は
$$ dy=v_{0y}dt-gdt^{2}k $$と表せます。これより、位置\(y\)は
$$ \begin{align} y&=\sum_{k=1}^{n}(v_{0y}dt-gdt^{2}k)\\ &=\sum_{k=1}^{n}v_{0y}dt-gdt^{2}\sum_{k=0}^{n}k\\ \end{align} $$と表せます。ここで
$$ \sum_{k=1}^{n}k=\frac{1}{2}n(n+1) $$です。よって、位置\(y\)は
$$ y=v_{0y}ndt-\frac{1}{2}gdt^{2}n(n+1) $$となります。ここで、\(n=\frac{t}{dt}\)とすると
$$ y=v_{0y}t-\frac{1}{2}g(t^{2}+tdt) $$と求まります。
・修正した式
位置\(x\),\(y\)の式は以下の通りです。
$$ \begin{align} &x=v_{0x}t\\ &y=v_{0y}t-\frac{1}{2}g(t_{2}+tdt) \end{align} $$Script
修正した式を用いた軌道予測線を描画するためのScriptは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
using System.Collections; using System.Collections.Generic; using UnityEngine; public class DrawLine : MonoBehaviour { public GameObject preLineRenderer; public GameObject preBullet; private GameObject objLineRenderer; private LineRenderer lineRenderer; private int count = 0; private float mass = 1f, drag = 1f, x = 0f, y = 0f, initVel = 10f, angle = 0f, step = 0.05f, time = 0; private float gravity = 9.80665f; private Vector3 vel; // Use this for initialization void Start () { angle = 30f * Mathf.Deg2Rad; vel = new Vector3(initVel * Mathf.Cos(angle), initVel * Mathf.Sin(angle), 0); objLineRenderer = Instantiate(preLineRenderer, gameObject.transform); objLineRenderer.transform.localPosition = Vector3.zero; lineRenderer = objLineRenderer.GetComponent<LineRenderer>(); Time.timeScale = 0.2f; } void DisZeroDrag() { if (y >= 0) { x = vel.x * time; y = vel.y * time - 0.5f * gravity * (time * time + time * Time.fixedDeltaTime); lineRenderer.positionCount = count + 1; lineRenderer.SetPosition(count, new Vector3(x, y, 0)); count++; time += step; } } // Update is called once per frame void Update () { DisZeroDrag(); } } |
実行結果
修正した軌道予測線があっているか否かを確認しました。結果は以下の通りです。この結果より、投射されたオブジェクトが修正した軌道予測線に沿って移動することがわかりました。
参考文献
-
前の記事
メッセージを表示するScript2 2018.07.22
-
次の記事
rigidbodyの軌道予測線を作成してみた(空気抵抗あり) 2018.08.09
コメントを書く