【Unity】Unityで万有引力

前回の記事でUnityにおいての重力について書かせていただきました。

現実の重力は地球の万有引力によるものなので、もっと掘り下げてみて万有引力を再現できないかなと思い今回万有引力を模したスクリプトを作成してみました。

ちなみに今回も2Dです。

はじめは月と地球を模して2点間の万有引力ということでがりがり進めていたのですが、値のスケールがとんでもないことになったり、動く速度が遅すぎたり(月の公転周期は1日なので・・・)と困りました。なので適当に値をいじりながら行いました。

 

結果としては月と地球、太陽と地球、宇宙ってすげぇ絶妙なバランスでできているんだなというものになりました。

 

万有引力について

まず万有引力についてなのですが、ざっくりいうと質量をもつすべて物体は他の物体をひきつける力をもつというものです。なので私達自身も万有引力で物体をひきつける力をもっています。でもそれは微力で現実に確認することは難しいでしょう。ただ地球というとんでもない質量をもつ万有引力は確認できます、地球の万有引力は重力という名で呼ばれている力です。

万有引力は以下の式で求めることができます。

f:id:graphicalpoxy:20190423144310p:plain

F:力

M:物体1の質量

m:物体2の質量

r:物体1・物体2の距離

G:万有引力定数(6.67408*10^-11)

万有引力の方向は引き合う力なのでそれぞれの物体の方向になります。

また万有引力は多質点を求めるものではなく、2点間の力を求めるものなので多質点系で計算したい場合は2点の組み合わせをすべて計算する必要があります。

今回は2点質点でシーンを動かしています。

 

宇宙には無数の星があるのでこの時点で宇宙のバランスすごいってなりますよね。

ただ物理は自然現象を数字で証明するためのものなので物理の上で考えると難しいだけで実際は単純なことが起きているのかもしれないと妄想してしまいます。

 

万有引力を再現する下準備

①シーン上にオブジェクトを2つ用意

②2つのオブジェクトにRigidBodyコンポーネントを追加

(③2つのオブジェクトになにかしらColiderコンポーネントを追加)

④Edit→ProjectSettingsのPhysics2Dのgravityを0に変更

以上です。

 

万有引力スクリプト作成

上記の公式で力を求めることが出来るということは、

運動方程式より

m{\boldsymbol  {a}}=m{\frac  {{\mathrm  {d}}^{2}{\boldsymbol  {r}}}{{\mathrm  {d}}t^{2}}}={\boldsymbol  {F}}

質量で割れば加速度を求めることが出来ます。

そしてそこで求めた加速度をオブジェクトにrgidbody.addForceしてあげると完成です。

以下がスクリプトになります。

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UniversalGravitationController : MonoBehaviour
{
    private float force;
    private float gravity;
    private Vector2 gravityVec;
    private Vector2 universalGravity;
    private float playerMass;
    [SerializeField]
    private GameObject obj;
    private float objMass;
    private float distance;
    private float G;

    private Rigidbody2D rb;

    // Start is called before the first frame update
    void Start()
    {
        //万有引力定数(今回はわかりやすいように変更しています)
        G = 6.6743f/ 100000; 
        playerMass = GetComponent<Rigidbody2D>().mass;
        objMass = obj.GetComponent<Rigidbody2D>().mass;
        rb = GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void Update()
    {
        //万有引力の加速度を計算

        //2点の距離計算
        distance = Vector2.Distance(transform.position, obj.transform.position);
        //万有引力計算
        force = G * playerMass * objMass / distance / distance;
        //求めた万有引力から加速度を計算
        gravity = force / playerMass;
        //万有引力の方向を計算
        gravityVec = (obj.transform.position - transform.position).normalized;
        //万有引力のベクトルを求める
        universalGravity = new Vector2(gravityVec.x * force, gravityVec.y * force);
        

        //動かす
        rb.AddForce(universalGravity);

    }
}

 

これを作成した2つの物体にそれぞれ追加し、インスペクタのobjに相手側のオブジェクトを入れてください。

 

 

初速を与えて公転を再現

このままでも万有引力は再現できると思います。

RigidBodyのMassの数値を弄ると挙動が変わってなかなか面白いですよね。

ここでは初速を与えることで公転っぽいことを再現させてみたいと思います。

以下のスクリプトを片側の物体に追加してください。

初速なのでstartのメソッドに書きます。

また速度はpublicにしているのでインスペクタで適当に数字を入れて挙動を試してみてください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MoonVelocityController : MonoBehaviour
{
    private Rigidbody2D rb;
    public float velocity;

    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        rb.velocity = new Vector2(0, velocity);
    }

    // Update is called once per frame
void Update() { } }

 

ちなみに私の実験結果では以下のような挙動をしています。

緒言は

M=1000000

Mの座標(0,0)

m=0.1

mの座標(5,0)

mの初速v=7

(ピンクが軌跡)

f:id:graphicalpoxy:20190423151735p:plain

計算すれば同じ軌跡を永遠にぐるぐるし続けるものが作れるのでしょうけど計算するのがめんどくさかったので、いろいろ数値をいじって物体が接触しないようにしました。

でも公転っぽいものがつくれたので個人的には満足しています。

今回作成したものの公転周期は一定ではないので、月と地球って絶妙なバランスの位置に存在しているんだなぁと思いました。(きれいに1日だから。)

またこの画像を見るとわかると思いますが、なんかぶっとんでいる時があるのがわかりますよね?でも月ってぶっ飛んでいかないちょうどいいところに存在しているんですよね、すげぇ!

また今回は2点でしたが、現実には星が無数にあるのでそれらがすべてかみ合って今が存在していると思うと感動しちゃいますね。

 

結論宇宙すげぇ