なめらかに移動させる簡単な方法

コラム

ある地点からある地点までオブジェクトをなめらかに移動させる際に、よく使う方法として Tweenがありますが、Tweenを使うまでもない場合などにもっと簡単に行う方法があります。
今回はその方法をご紹介します。

まずは土台を作ります。
(UnityでC#を使って作成しています)

このプログラムはマウスのボタンが押されたら、表示物をマウスカーソルに移動させる処理です。
実際に実行すると動画のような動きになります。

一瞬で移動しますね。
ここを滑らかに移動するよう処理を追加します。

プログラムを少し修正しました。
マウスカーソルの座標をそのまま入れるのではなく、ローカル変数の中に値を入れて、その値を座標に足すようにしています。
このようにした結果、移動はこのようになります。

ずいぶんスムーズに動くようになりました。
目的地に近づくにつれて速度が落ちるので、滑らかに見えますね。
プログラムの内容ですが、現在地と目的地の距離を出し、その2割分(0.2)を移動するという処理になっています。
例えば距離が100mだったとすると、1回目の移動で20m進み、2回目の移動で16m(80mの2割)進み、3回目の移動で12.8m(64mの2割)進みます。
つまり目的地までの距離が短くなるにつれて、1回の移動量が減るわけです。
これが滑らかに移動する理由です。

Tweenを使う場合は移動時間を指定する必要がありますが、この方法の場合は移動時間を指定する必要がないのも手軽です。
また移動中に目的地が変わっても、良い感じで追従してくれます。


ただしこの方法には制限があって、フレームレートが一定である必要があります。
1回の実行で全体の2割分を移動するというアルゴリズムなため、フレームレートが変わると移動スピードが変化してしまいます。
試しに強制的にフレームレートを60FPSから10FPSに変えて実行してみます。

フレームレートが落ちるので動きがカクカクするのは仕方ないにしても、移動速度が落ちてしまうのは問題になるかもしれません。
フレームレートが変わっても、同じ時間で同じ場所に移動させるにはどうしたら良いでしょうか?

例えばデフォルトが 60フレームの場合、30フレームになった場合は、1度に2回処理をさせてやる必要があります。
係数で考えると、60フレームで動いている場合は距離に 0.2をかけますが、30フレームになった場合は、2フレーム分の 0.36を掛ける必要があります。
0.2 + 0.16 の累計になるわけですね。
これが2フレーム分を一気に進ませる際に必要になる係数です。

「0.2を 2回だから 0.4じゃないの?」って思った人は上の図を見返してみて、2回の移動で何mすすんだかを確認してみてください。


さてもう少し複雑なケースを考えます。
1.5フレーム分を一気に進ませる際に必要になる係数はいくつでしょうか?

まず1回目の移動はそのまま 2割進みます。
2回目の移動は、2割の半分になりますね。
なので、係数の計算は 0.2 + 0.16 * 0.5 で 0.28になります。

ここで、2フレーム目の係数の出し方を考えてみます。
2フレーム目の係数は、1フレーム目の係数の 2割を引いた値になります。
0.2の 2割は 0.04 なので、0.2 – 0.04 = 0.16 となるわけです。
3フレーム目の係数は、2フレーム目の係数の 2割を引いた値になるので、
0.16 – 0.16 * 0.2 = 0.128 となります。

これらを答えとして出す方程式を考えます。

完成したら実際に動きを確認してみます。

さきほどよりも動きが速くなっています。
実際に60FPSの状態のものと比較してみましょう。

フレームレートが落ちるので動きがカクカクしてるのは仕方ないですが、移動スピードが一緒になってるので到着時間がほぼ同じになっていますね。


今回の方法はフレームレートが変動する場合は多少処理が面倒になりますが、フレームレートが安定している場合や、フレームレートの変動を気にする必要がない場合などは、とても簡単に実装することができます。

例えばカメラの移動を少し滑らかにしたい場合などにも使えます。
ぜひ活用してみてください。

あともう一点注意として、アルゴリズムの性質上、いつまで経ってもゴールには到着しません。
どうしてもゴールにピタリと到着させたい場合は、残り移動距離が一定の範囲内になったら強制的に移動してやるなどの処理が必要になります。

コメント

タイトルとURLをコピーしました