単純な物理
ゲームでよく使われそうな物理を練習しましょう。以下の処理は、Unity の Rigidbody を対応してくれる処理である。
移動、速度、加速度
移動と速度の関係性
次の状況を考えてみてください:あるキャラクターは2D空間の位置「p = (px, py)」にいる。このキャラクターは定めた時間「Δt」をかけて、ある目的地「q = (qx, qy)」に到着させたい。
この場合は、移動に必要な速度「v = (vx, vy)」を求めることができる:
|
|
始点「p」から終点「q」までの距離(と向き)を到着までの必要な時間で割ると、速度「v」を求める。それでは、始点「p」と速度「v」があれば、定めた時間「t」の後に、どこにいるか知りたいなら:
|
|
Unityでは、フレーム間の時間を「Time.deltaTime」で取得できるので、移動を計算したいなら:
// 始点(現在の位置)
Vector3 p = transform.position;
// vは「Vector3」型の速度(量と向き)
Vector3 q = p + v * Time.deltaTime;
// 位置を更新
transform.position = q;
練習
シーンに何かの3Dオブジェクトを追加。スペースキーを押したら、一定速度で移動する。キーを放したら、速度を0にする。速度を Inspectorで設定できるようにしてください。
TestVelocityのスクリプト
// 物理の練習:一定速度で移動
public class TestVelocity : MonoBehaviour
{
// 速度ベクトル(量+向き)
[SerializeField]
private Vector3 velocity;
void Update()
{
// まず、速度はゼロにする
Vector3 v = Vector3.zero;
// 何かのキーを押したら
if (Input.GetKey(KeyCode.Space))
v = velocity; // 速度を書き換える
// 物理演算を使って、移動する
Vector3 p = transform.position;
// 移動の式
Vector3 q = p + v * Time.deltaTime;
// 位置更新
transform.position = q;
}
}
加速度
速度は「時間単位当たりの物体の位置の変化量」であるとしたら、加速度は「時間単位当たりの物体の速度の変化量」である(速度の速度)。つまり:
|
|
速度「v」は、初期速度「v0」に加速度「a」と加速した時間「Δt」の乗算を足す。Unityで実装するなら:
// 内部の速度ベクトル
private Vector3 velocity;
private void Update()
{
// 初期速度
Vector3 v0 = velocity;
// 新しい速度を計算
Vector3 v = v0 + a * Time.deltaTime
// 次のフレームの初期速度を更新
velocity = v;
}
練習
加速度を試せる TestAccel のスクリプトを作成してください。「A」キーを押したら一定加速度で移動する。「S」キーを押すと一定速度で減速する。速度が0以下にならないようにする。なお、加速度を Inspectorで設定できるようにしてください。
TestAccelのスクリプト
// 物理の練習:加速度
public class TestAccel : MonoBehaviour
{
[SerializeField]
Vector3 acceleration; // 加速度ベクトル(量+向き)
Vector3 velocity; // 速度(内部)
void Update()
{
// まずは、速度を更新
Vector3 a = Vector3.zero; // 加速なし
// 「a」を押したら、加速
if (Input.GetKey(KeyCode.A))
a = acceleration;
// 「s」を押したら、減速
else if (Input.GetKey(KeyCode.S))
a = -acceleration;
// 現在の速度
velocity = velocity + a * Time.deltaTime;
// 位置を更新(移動)
Vector3 p = transform.position;
Vector3 q = p + velocity * Time.deltaTime;
transform.position = q;
}
}
重力
重力は下に向かう加速度ベクトルである。地球の場合は、おおよそ 9.81 m/s2 である。
// 重力ベクトル
Vector3 gravity = new Vector3(0, -9.81f, 0);
練習
ボールを投げるスクリプト「ThrowBall」を作成する。Inspectorでボールに初期速度を設定し、斜め上に投げ、重力で落とす。無限に落ちないように、Y軸の位置は0以下にならないようにする。
|
v0 の初期速度にてボールを投げる。 g 重力の加速度であり、時間により落下してくる。 |
ThrowBall スクリプト
// ボールを投げ、重力で落とす
public class ThrowBall : MonoBehaviour
{
// ボールの初期速度
[SerializeField]
private Vector3 velocity;
private void Update()
{
// 重力による加速度を使い、速度を更新
Vector3 gravity = new Vector3(0, -9.81f, 0);
velocity += gravity * Time.deltaTime;
// 位置を更新
var position = transform.position;
position += velocity * Time.deltaTime;
// 高さが0以下にならないようにする
position.y = Mathf.Max(0, position.y);
transform.position = position;
}
}
質量、力と加速度の関係性
すべての物体は「質量」があり、重ければ重いほど動かすのは力が必要。従って、物体の加速度は、物体の重さ(質量)と力に依存する。その関係性以下の通りである:
|
|
ここで、「a」は加速度であり、「f」は力、「m」は質量である。これは「Rigidbody.AddForce」の処理である。
練習
ThrowBall を更新し、ボールに質量を与え、キーを押したら力を与える。力のベクトルと質量をInspectorで変えられるようにする。
|
m はボールの質量である。 f は投げる力である。 g 重力の加速度であり、時間により落下してくる。 |
ThrowBall スクリプト
// ボールを投げ、重力で落とす
public class ThrowBall : MonoBehaviour
{
// ボールの質量
[SerializeField]
private float mass;
// 投げる力
[SerializeField]
private Vector3 force;
// 速度(内部)
private Vector3 velocity;
private void Start()
{
// 力と質量から加速度を計算
Vector3 a = force / mass;
// 加速度は時間をかけて速度を変える
// 投げる時間を 0.5秒にしましょう
velocity = a * 0.5f;
}
private void Update()
{
// 重力による加速度を使い、速度を更新
Vector3 gravity = new Vector3(0, -9.81f, 0);
velocity += gravity * Time.deltaTime;
// 位置を更新
var position = transform.position;
position += velocity * Time.deltaTime;
// 高さが0以下にならないようにする
position.y = Mathf.Max(0, position.y);
transform.position = position;
}
}