【Unity】滑らかに変化する処理を作るSmoothDampとは?

SmoothDampとは? Unity

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、

「UnityのSmoothDampってなに?」

「SmoothDampメソッドの使い方が知りたい!」

というお悩みの方に向けた内容となっています。

Unityでは、滑らかな移動処理などを作る際に、SmoothDampメソッドが使われることがあります。

このSmoothDampは、目的となる場所、そして到達時間を指定することで、その目的に時間をかけて到達するように滑らかに変化させる処理を行ってくれるメソッドです。

オブジェクトの移動処理やカメラの回転、ズーム処理など、滑らかに遷移させたい場合に使えます。

そこで、このページでは、SmoothDampメソッドについて、どんなメソッドなのか、また使い方までをまとめていきます。

この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

SmoothDampとは?

まずは、SmoothDampメソッドがどういうメソッドなのか、紹介していきます。

滑らかに数値やベクトルを変化させるメソッド

SmoothDampメソッドは、滑らかに数値やベクトルを変化させる処理を行う、Vector3Mathfの構造体で定義されているメソッドです。

もう少し具体的に言うと、SmoothDampメソッドは、現在の数値やベクトルを、指定した目的となる数値やベクトルに向かって、徐々に変化させた値を返すという処理を行っていて、この取得した値を使うことで滑らかに遷移させることができます。

例えば、オブジェクトの座標の位置を移動させる場合、SmoothDampメソッドで目標となる座標位置を指定してあげます

すると、フレーム毎に変化した座標位置を返してくれるので、その値をオブジェクトの座標位置に入れてあげることで、オブジェクトを滑らかに移動させることができます。

Lerpと違い時間や速度を直接指定できる

SmoothDampメソッドと同様に、滑らかな遷移処理を作るのに、Lerpメソッドも使われることがあります。

このLerpメソッドは、現在の値と目標の値の2つの間の値を、線形補間によって求めることで、オブジェクトを移動させたり、数値の変化を行うことができるメソッドです。

Lerpメソッドとの違いとして、SmoothDampメソッドは時間速度を考慮して移動処理を行うことができます。

例えば、Lerpメソッドの場合、2つの間に直線があると想定して、その直線に沿って指定した割合(補間位置)の値をフレーム毎に返すことで移動させていきます。

しかし、SmoothDampメソッドの場合は、目的に到達するまでの時間を指定することで、フレーム毎の経過時間から速度を自動で計算し、指定した時間で到達する数値を返すことで移動させていきます。

また、最大速度を指定することもできるので、オブジェクトが速く動いてしまう場合などでは、速度制限を付けることもできます。

ただし、速度制限をかけると、指定時間よりも遅れてしまうことがあるため、注意しておきましょう。

SmoothDampの使い方

ここからは、SmoothDampメソッドの使い方について紹介していきます。

SmoothDampの記述方法

Vector3型のSmoothDampメソッドを使う際は、以下のように引数を使って記述することで、目的の値に向かって変化させたVector3型の値を取得できます。

Vector3.SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, deltaTime);

current:現在のベクトル(Vector3型)。
target:目標となるベクトル(Vector3型)。
currentVelocity:現在の移動速度を取得する変数(Vector3型)。頭に「ref」を付けて参照渡し。
smoothTime:目標に到達するまでにかかるおおよその時間(float型)。
maxSpeed:移動する際の最大速度(float型)。省略可能。
deltaTime:最後に関数が呼び出されてからの経過時間(float型)。省略可能。

第1引数に現在のベクトル値(current)、第2引数に目標とするベクトル値(target)を設定します。

第3引数は、SmoothDampで変化させる際の現在の速度を取得する変数(currentVelocity)を設定します。

この変数は、SmoothDampの処理が行われる度に更新され、また参照渡しする必要があるため、頭に「ref」を付けます。

第4引数に、到達するまでのおおよその時間(smoothTime)秒数で指定してあげます。

第5引数は、変化させる際の最大となる速度(maxSpeed)を指定することができ、省略した場合は「Mathf.Infinity」となり、速度制限がかかりません。

最後の第6引数は、SmoothDampの関数が最後に呼び出されてからの経過時間を指定する値(deltaTime)で、省略するとフレーム毎の経過時間となる「Time.deltaTime」の値となるので、基本は省略で良いかと思います。

なお、Mathf型の場合は、currenttargetcurrentVelocityの部分の値をfloat型で指定すれば、変化後の値がfloat型で取得できます。

SmoothDampの使用例

ここからは、実際にSmoothDampメソッドを使った使用例を紹介していきます。

オブジェクトをSmoothDampで移動させる

まずは、シンプルにオブジェクトの座標位置をSmoothDampメソッドを使って移動させる処理を作ってみます。

以下のように、球体のオブジェクトを配置して、目標とする位置に空オブジェクトを配置しておきます。

そして、球体のオブジェクトに以下のスクリプトをアタッチしておきます。

using UnityEngine;

public class Test : MonoBehaviour
{
    public GameObject target;   // 空オブジェクトを取得
    Vector3 velocity = Vector3.zero;    // 現在の速度を取得する変数

    void Update()
    {
        transform.position = Vector3.SmoothDamp(transform.position, target.transform.position, ref velocity, 1.0f); // オブジェクトの座標位置を移動させる処理
    }
}

10行目でVector3.SmoothDampメソッドを使って、目標位置まで変化させる値を自身のtransform.positionに代入しています。

また、SmoothDampの第1引数の現在の位置に、transform.positionで自身の座標位置を入れてあげることで、関数が呼び出されるたびに値が変化していくことになります。

そして、第3引数の現在の速度を取得する変数には、6行目のようにVector3.zeroで初期値を入れていて、refを付けて指定しています。

これでゲームを実行してみると、

オブジェクトが目標位置に向かって、滑らかに移動しているのが分かります。

特定のオブジェクトに滑らかに追従させる

次は、SmoothDampメソッドを使って、特定のオブジェクトに追従させる処理を作ってみます。

まずはカプセル型のオブジェクトを配置して、キー操作で左右に移動する処理を書いたスクリプトをアタッチしておきます。

using UnityEngine;

public class CapsuleController : MonoBehaviour
{
    void Update()
    {
        transform.position += new Vector3(Input.GetAxis("Horizontal") * 0.01f, 0f, 0f); // オブジェクトをキー操作で横移動させる処理
    }
}

次に、この移動するオブジェクトに追従させるキューブ型のオブジェクトを配置します。

そして、このキューブのオブジェクトに以下のスクリプトをアタッチしていきます。

using UnityEngine;

public class Test2 : MonoBehaviour
{
    public GameObject target;   // 目標となるオブジェクト情報
    float targetPositionX;  // 目標のオブジェクトのX座標
    float velocity = 0.0f;  // 現在の速度を取得する変数
    int direction = 1;  // 移動方向を取得する変数

    void Update()
    {
        // キー操作による移動方向を取得する処理
        if (Input.GetAxis("Horizontal") > 0)
        {
            direction = 1;
        }
        else if (Input.GetAxis("Horizontal") < 0)
        {
            direction = -1;
        }

        targetPositionX = Mathf.SmoothDamp(transform.position.x, target.transform.position.x - direction * 1.5f, ref velocity, 0.5f); // 目標に向かうX座標の変化した値を取得
        transform.position = new Vector3(targetPositionX, transform.position.y, transform.position.z);  // 自身の座標位置を更新する
    }
}

22行目でMathf.SmoothDampメソッドを使って、自身のX座標から目標とするオブジェクトのX座標へ変化させる値を取得しています。

これでゲームを実行してみると、

カプセル型のオブジェクトの移動に合わせて、キューブのオブジェクトが追従できているのですが、方向転換したときに急に動きが少し速くなってしまっています。

そこで、SmoothDampメソッドに速度制限をかけてみます。

using UnityEngine;

public class Test2 : MonoBehaviour
{
    public GameObject target;   // 目標となるオブジェクト情報
    float targetPositionX;  // 目標のオブジェクトのX座標
    float velocity = 0.0f;  // 現在の速度を取得する変数
    int direction = 1;  // 移動方向を取得する変数

    void Update()
    {
        // キー操作による移動方向を取得する処理
        if (Input.GetAxis("Horizontal") > 0)
        {
            direction = 1;
        }
        else if (Input.GetAxis("Horizontal") < 0)
        {
            direction = -1;
        }

        targetPositionX = Mathf.SmoothDamp(transform.position.x, target.transform.position.x - direction * 1.5f, ref velocity, 0.5f, 2.5f); // 目標に向かうX座標の変化した値を取得
        transform.position = new Vector3(targetPositionX, transform.position.y, transform.position.z);  // 自身の座標位置を更新する
    }
}

22行目で、SmoothDampメソッドの第5引数に速度制限として、「2.5」の値を設定してみました。

もう一度ゲームを動かしてみると、

方向転換時の動きが速度制限によってゆっくりになり、違和感が無くなりました。

まとめ

このページでは、Unityで使えるSmoothDampについて、どんなメソッドなのか、また使い方までを紹介していきましたが、いかがでしたでしょうか?

SmoothDampメソッドは、目的となる値まで徐々に変化させて滑らかな遷移処理を行うことができるメソッドです。

同じように滑らかな処理を行うLerpメソッドと違って、到達までの時間や速度を指定することができるので、より安定した遷移処理を作ることができます。

オブジェクトを追従させる処理や、カメラのズームや回転などで滑らかな処理を作りたい場合は、SmoothDampメソッドが便利です。

最後までお読みいただきまして、ありがとうございました!

コメント