[Unity] 惑星に向かって物体が落ちるようにする

前回の記事で個別のゲームオブジェクトに対して重力加速度を与える方法について紹介しました。

今回はこの応用として引力の発生する小さな惑星に物体が落ちるような動きを実現してみたいと思います。

・単純な方法
大きさが一定の加速度ベクトルを球体の中心に向かせれば惑星に物体が落下するようになります。

using UnityEngine;
using System.Collections;

public class PlanetGravity : MonoBehaviour {
    public GameObject planet;       // 引力の発生する星
    public float accelerationScale; // 加速度の大きさ
	
	void FixedUpdate () {
		// 星に向かう向きの取得
		var direction = planet.transform.position - transform.position;
		direction.Normalize();

		// 加速度与える
		rigidbody.AddForce(accelerationScale * direction, ForceMode.Acceleration);
	}
}

これで以下のように惑星に向かってものが落ちていくようになります。

planet-gravity-1

・万有引力の法則を使う
上記の方法では惑星からどれだけ離れても重力加速度の大きさは一定です。
しかし、実際は惑星から離れるほど小さくなって行きます。
これは以下のような万有引力の法則に基づいて決まります。

F = G \cfrac{m_1 m_2}{r^2}
 
Gは定数、m_1, m_2は落下する物体の質量、rは惑星からの距離です。
より正確な動きを再現する場合は上記の数式に使われるパラメータを定めて式を実装する必要があります。

実際のスクリプトにすると以下のような感じになります。

using UnityEngine;
using System.Collections;

public class PlanetGravityEx : MonoBehaviour {
	public GameObject planet;	// 引力の発生する星
	public float coefficient;	// 万有引力係数
	
	void FixedUpdate () {
		// 星に向かう向きの取得
		var direction = planet.transform.position - transform.position;
		// 星までの距離の2乗を取得
		var distance = direction.magnitude;
		distance *= distance;
		// 万有引力計算
		var gravity = coefficient * planet.rigidbody.mass * rigidbody.mass / distance;
		
		// 力を与える
		rigidbody.AddForce(gravity * direction.normalized, ForceMode.Force);
	}
}

これで以下のように複数個の惑星があっても各星に向かって物体が落ちていくようになります。

planet-gravity-2

上記のスクリプトは惑星に対して引力を作用させることはやっていないので、厳密に実装する場合はフィールド上に存在する物体をすべて検索で取得し、相互作用を及ぼすようにする必要があるでしょう。
しかし、惑星が動かないことが前提なら上記のように多少手抜きをして計算量を減らしたほうがよいと思います。(フィールドに存在する物体の2乗に比例して計算量が増大するため)

万有引力の法則に従って重力加速度を発生させているので、物体が惑星の周りを回る動作も再現できます。
宇宙船がスイングバイするゲームや惑星同士が戦うゲームなども作れそうですね。

■参考サイト
万有引力の法則・定理のまとめ / 物理 by 藤山不二雄 |マナペディア|