【Unity】オブジェクトに加速度を与えて加減速させる

オブジェクトを加速させたり減速させたりする方法を教えてほしいの~!

やり方は主に2通りあるわ。加減速の処理を自分で実装する方法と、Rigidbodyを用いる方法ね。

オブジェクトを加速させたり減速させたりする方法の紹介です。

本記事では、次の2通りの方法を紹介します。

加減速させる方法
  • 与えられた加速度から自前で加減速する処理を実装する
  • RigidbodyのAddForce()メソッドで加速度を指定する

両者ともスクリプトで実装する形となります。

前者は自前で実装する必要がある分、汎用性の高い方法です。
後者はRigidbodyを使う必要があるものの、簡単に加減速が実現できる方法です。

本記事では、これらの加減速をスクリプトから行う方法について、例を示しながら解説していきます。

動作環境
  • Unity2021.1.25f1

加減速処理を自前で実装する

オブジェクトの加減速は、加速度ベクトルを用いて実現できます。

以下、オブジェクトを指定された加速度で加減速させるサンプルスクリプトです。

ObjectAccelerator.cs
using UnityEngine;

public class ObjectAccelerator : MonoBehaviour
{
    // 加速度
    [SerializeField] private Vector3 _acceleration;

    // 初速度
    [SerializeField] private Vector3 _initialVelocity;

    // 現在速度
    private Vector3 _velocity;

    private void Start()
    {
        // 初速度で初期化
        _velocity = _initialVelocity;
    }

    private void Update()
    {
        // 加速度の時間積分から速度を求める
        _velocity += _acceleration * Time.deltaTime;

        // 速度の時間積分から位置を求める
        transform.position += _velocity * Time.deltaTime;
    }
}

Accelerationに加速度ベクトルを、Initial Velocityに初速度ベクトルを指定します。

実行結果

速度と同じ向きに加速度を与えると加速し、反対向きに加速度を与えると減速します。速度と斜め向きに加速度を与えると、放物線を描く軌道になります。

加速度から現在位置が求まる理由

前述のスクリプトで加減速処理が実現できる理由についても触れておきます。

加速度から速度を計算する

速度は、加速度を時間積分することで計算できます。

ここで言う時間積分は、下図の赤い部分から青い部分面積を引いた値を求めることに相当します。

横軸は時刻、縦軸は加速度です。 [1]

ただし、先述の例のように毎フレーム毎に加速度から速度を計算する場合、次のような長方形に近似した面積を使用する形になります。 [2]

そのため、値には誤差が発生します。しかし、フィールド上を動き回るオブジェクトなど、誤差が気にならないケースでは問題ないでしょう。

あるフレームnにおける速度v_nは、1つ前のフレームにおける速度v_{n-1}を用いて、次のように計算できます。

加速度から速度を近似的に求める式
v_n = v_{n-1} + a_n {\Delta t}_n
a_n{\Delta t}_nはそれぞれフレームnにおける加速度と前フレームからの経過時間です。

ベクトルの積分では、xyz成分それぞれで上記を計算します。

速度から位置を計算する

位置は、速度を時間積分することで計算できます。加速度から速度を求める計算と同じ要領です。

フレームnにおける位置p_nの計算は、次式のようになります。

速度から位置を近似的に求める式
p_n = p_{n-1} + v_n {\Delta t}_n

加速度から現在位置を求める処理

ここまで説明した時間積分の計算処理は、最初に示したスクリプトの次の部分に対応します。

// 加速度の時間積分から速度を求める
_velocity += _acceleration * Time.deltaTime;

// 速度の時間積分から位置を求める
transform.position += _velocity * Time.deltaTime;

普段から何気なくdeltaTimeを使っていた移動も、このような原理で動いていたのね😮

この原理を抑えておけば、色々な場面で応用が利くのでとても便利だわ!

RigidbodyのAddForce()メソッドで加減速させる

Rigidbodyで物理演算されているオブジェクトの場合、Rigidbody.AddForce()メソッドに加速度を指定することで加減速ができます。

public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force);

加速度を与えたい場合、第1引数に加速度ベクトル、第2引数にForceMode.Accelerationを指定します。

サンプルスクリプト

RigidbodyAccelerator.cs
using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class RigidbodyAccelerator : MonoBehaviour
{
    // 加速度
    [SerializeField] private Vector3 _acceleration;

    private Rigidbody _rigidbody;

    private void Awake()
    {
        _rigidbody = GetComponent<Rigidbody>();
    }

    private void FixedUpdate()
    {
        // AddForceで加速度を指定
        _rigidbody.AddForce(_acceleration, ForceMode.Acceleration);
    }
}

物理演算が有効なRigidbodyがアタッチされているオブジェクトでないと機能しないことにご注意ください。インスペクタのAccelerationに加速度を指定します。

実行結果

さいごに

オブジェクトの加減速処理は、時間積分を駆使して実現できます。

Rigidbodyで物理演算されている場合は、AddForce()メソッドから行う形になります。

今回はオブジェクトの移動に対する加減速を紹介しましたが、原理を抑えると回転にも応用できます。

【Unity】ゲームオブジェクトの移動・回転・拡大縮小のきほん
Transformとは ゲームオブジェクトの移動・回転・拡大縮小を行うためのものです。Transformはコンポーネントの一種で、ゲームオブジェクトに必ず1つ存在します。 Unityエディタのゲームオブ ...

参考サイト