オブジェクトを滑らかに追従させる方法ってないの~?
UnityのSmoothDampメソッドを使えば簡単だわ!
Unityには目標値に滑らかに向かう変化を実現するSmoothDamp系メソッドが用意されています。
- Mathf.SmoothDamp
- Vector2.SmoothDamp
- Vector3.SmoothDamp
- Mathf.SmoothDampAngle
これらのスムージングは、目標に近づくにつれて減速し、最終的に目標値になるような動きをします。
ほかによく用いられる方法としてLerpメソッドを使う方法がありますが、これと比較してSmoothDampメソッドには以下のメリットがあります。
- フレームレートに依存しない
- 目標値に到達するまでのおおよその時間を指定できる
- 最大速度を指定できる
上記を考慮したスムージングを実装しようとすると、少々複雑な処理を考えなければいけませんが、この問題もSmoothDampメソッドを用いれば解決できます。
本記事では、SmoothDampメソッドを使い、フレームレートに依存しない滑らかな追従を実現する方法について解説します。
この作品はユニティちゃんライセンス条項の元に提供されています
- Unity2021.1.11f1
目次 非表示
Mathf.SmoothDamp()メソッド
float型の値を滑らかに目標値に追従させるメソッドです。
このメソッドを毎フレーム実行することで滑らかな追従を実現します。
メソッド形式
メソッドの形式は以下の通りです。
第1引数currentには、現在値を指定します。
この値を基準に次の値が計算されます。
第2引数targetは目標値です。
最終的に行き着く先の値を指定します。
第3引数currentVelocityには、現在速度を格納する変数を指定します。
SmoothDamp関数内部で計算のために使われます。
先頭についているrefは参照渡しを示すC#のキーワードです。
変数の参照を渡すことで、その変数の値を呼び出されるメソッドから読み書きできるようになります。
第4引数smoothTimeには、目標値に到達するまでのおおよその時間を秒数で指定します。
おおよそなので、厳密にこの時間が掛かるという訳ではありません。
第5引数maxSpeedには、値変化するときの最高速度を指定します。
指定が省略された場合は、Mathf.Infinityすなわち正の無限大が指定されます。これにより、制限速度の上限を無くすことが可能です。
第6引数deltaTimeには、この関数が最後に呼び出されてからの経過時間を指定します。
指定が省略された場合は、Time.deltaTimeの値となります。
戻り値は、変化後の値です。
次フレームにMathf.SmoothDampメソッドを呼び出す時、第1引数currentに指定する値になります。
参考:Mathf-SmoothDamp – Unity スクリプトリファレンス
サンプルスクリプト
あるオブジェクトのx座標をターゲットに追従させるサンプルスクリプトです。
上記スクリプトを適当なゲームオブジェクトにアタッチして、_targetに追従対象のターゲット、_followerに追従させるオブジェクトを指定してください。必要に応じて_smoothTimeと_maxSpeedも調整してください。
実行結果
ターゲットに向かってx座標が滑らかに遅れて追従していることが分かります。
Vector2.SmoothDamp()メソッド
Mathf.SmoothDamp()メソッドのVector2版です。
2次元座標単位で滑らかな追従を実装したい場合に重宝します。
メソッドの形式は以下の通りです。
Mathf.SmoothDamp()メソッドと比較して、第1~3引数がfloat型からVector2型に変わったところ以外は一緒です。
参考:Vector2-SmoothDamp – Unity スクリプトリファレンス
Vector3.SmoothDamp()メソッド
Mathf.SmoothDamp()メソッドのVector3版です。
メソッドの形式は以下の通りです。
こちらも、第1~3引数がVector3型になっている点以外はMathf.SmoothDamp()メソッドと一緒です。
参考:Vector3-SmoothDamp – Unity スクリプトリファレンス
Mathf.SmoothDampAngle()メソッド
Mathf.SmoothDamp()メソッドの角度対応版です。
向きなどの角度に対して滑らかな追従をしたい場合に役立ちます。
角度は内部的に正規化して計算されるため、360度以上やマイナスなどの角度でも問題なく計算できます。
メソッドの形式
メソッドの形式は以下の通りです。
引数の形式はMathf.SmoothDamp()メソッドと一緒です。
current、targetには度数法の角度を指定します。
戻り値には、度数法表記の正規化された角度が返されます。
参考:Mathf-SmoothDampAngle – Unity スクリプトリファレンス
サンプルスクリプト
指定されたターゲットの方向に滑らかに回転するスクリプトの例です。
実行結果
Lerpと比較した場合のメリット
スムージングを実現するのによく見かける方法として、Lerpメソッドを用いる方法があります。しかし、この方法にはフレームレートによって動きが変わってしまう可能性のあるデメリットが存在します。ただ、実装次第である程度変化を抑えることは可能です。
SmoothDamp系メソッドは、フレームレートによらず動きがほぼ一定になるメリットがあります。
検証用スクリプト
異なるフレームレートの動作検証用として、Lerpを使う方法、SmoothDampを使う方法それぞれでフレームレートを変えられるスクリプトを用意しました。
Lerpの検証用スクリプト
SmoothDampの検証用スクリプト
実行結果
Lerp、SmoothDampそれぞれのスクリプトでの実行結果です。
更新周期を0.5秒、0.1秒で追従するオブジェクトを並べて比較してみました。
Lerpの実行結果
移動中の位置が周期で若干ずれていることが分かります。
SmoothDampの実行結果
移動中の位置が周期によらずほぼ一致する結果となりました。
さいごに
本記事では、スムージングの便利メソッドSmoothDampについて解説しました。
Lerpメソッドで実装するのが簡単ですが、実装によってはフレームレートによって挙動が変化してしまう問題があります。
SmoothDamp系メソッドは、この問題を複雑な実装を要求せずに解決してくれます。
Lerpメソッドでも工夫次第ではこの問題を解決できますが、特に拘りがない限りはSmoothDampメソッドを使うのが楽です。
様々な場面で活躍できるでしょう。