おもちゃラボ

Unityで遊びを作ってます

【Unity】落下地点の座標から、放物線の方程式を求める

落下地点が決まっていて、そこに向かって弾をとばしたり、ミサイルを撃ち込みたいことがあります。落下地点から放物線の方程式を求めるのって、結構難しいんですよね・・・。

ということで、ここでは、打ち出し角度と落下地点の座標を指定することで放物線の係数をもとめる方法を紹介します。

f:id:nn_hokuson:20170526213726p:plain:w600

これにより、指定した落下地点に確実に落下するミサイルなどを作ることが出来ますよ!記事の内容は次のとおりです。

放物線の求め方

放物線を求めるのに必要な情報として次の2つを与えます。

  • 落下地点の座標
  • 射出角度

ただし、打ち出す場所は原点とします。原点以外から撃つ場合は、オフセットを足してあげればOKです。この情報をもとに図を書くとこんな感じになります。

f:id:nn_hokuson:20170526214134p:plain:w500

求める放物線はf(x)=ax^2+bx+cと書けます。コレに上の条件をあたえると・・・

f(0)=0より、c = 0
f(target.x)=target.yより、target.y = a*target.x^2+b*target.x
f'(0)=tan(deg)より、b = tan(deg)

この連立方程式を解くと

a = (target.y - b * target.x) / (target.x * target.x)
b = tan(deg)

と、比較的簡単に放物線の方程式を求めることが出来ます。

放物線を求めるプログラム

落下地点の座標から放物線をもとめるスクリプトは次のようになります(ここでは、実際に放物線の方程式を求めているボールのスクリプトを示しています)

public class BallController : MonoBehaviour {

    public GameObject block;
    Vector3 offset;
    Vector3 target;
    float deg;
 
    IEnumerator ThrowBall()
    {
        float b = Mathf.Tan (deg * Mathf.Deg2Rad);
        float a = (target.y - b * target.x) / (target.x * target.x);
      
        for (float x = 0; x <= this.target.x; x+= 0.3f)
        {
            float y = a * x * x + b * x;
            transform.position = new Vector3 (x, y, 0) + offset;
            yield return null;
        }
    }

    public void SetTarget(Vector3 target, float deg)
    {
        this.offset = transform.position;
        this.target = target - this.offset;
        this.deg = deg;

        StartCoroutine ("ThrowBall");
    }

    void Start()
    {
        // ブロックに向かって60度の角度で射出
        SetTarget ( block.transform.position, 60 );
    }
}

SetTargetメソッドで、ボールの落下地点の座標(target)と、ボールの射出角度(deg)を指定しています。この例では、落下地点はブロックの位置、射出角度は60度を指定しています。射出地点を原点にするためoffsetを保存してから、放物線の係数を計算しています。ThrowBallコルーチンの中で、現在のx座標と放物線の方程式からy座標を求めています。最後にoffsetを戻してボールの位置に反映しています。

実行結果

クリックした点にボールが飛んで行くように修正したプログラムの実行結果がこちらです。

f:id:nn_hokuson:20170526215539g:plain

ここでは射出角度を、射出座標と落下座標のなす角度から求めています。