(この記事にはProcessing.jsによるスケッチがいくつか組み込まれています。環境によっては正しく再生されないかもしれません。Chrome, Safari, Firefox等の使用をおすすめします。)
「丸が1秒おきに左右に滑らか動く」というプログラムを書いてみよう。いちばん簡単なのは、線形移動を使う方法だ。
まあ、これでも十分っちゃ十分なんだけれど、動きとしてはちょっと味気ない。
いわゆるイーズアウト(ease out)を使えば、これを滑らかにすることができる。
上のスケッチでは、漸化式を使ったイーズアウトを実装している。こんな感じの式だ。
pos += (target - pos) * 0.1;
pos
は現在座標、 target
は目標の座標。この式を1回の描画毎に評価する。目標座標までの差分を1割づつ詰めていくような感じ。差分は毎回少なくなっていくから、最初は早く、徐々に遅く、という動きが出来上がるわけ。
この動きは、数式的には指数関数で表すことができる。グラフにプロットすると、だいたいこんな感じだ。
この方法は、特に変数を追加しなくても実装できるというのがいいところだ。
ただ、この方法には致命的な弱点がある。それは、フレームレートによって動きが変化してしまうということだ。例えば、上のスケッチのフレームレートを10に落とすと、下のようになる。
動きの勢いが違うし、しかも時間内に目標座標まで到達できていない。
これはフレームレートが変化しうる条件下では致命的な欠点だ。UIなら操作のフィーリングが変わってしまうし、ゲームなら難易度が変化してしまうかもしれない。
この問題を解決するには、上で例示した指数関数を、フレームレートを含んだ形で漸化式に直せばいい。過程は省略するけれど(高校数学の指数関数を思い出して!)こんな感じの式になる。
pos += (target - pos) * (1.0 - exp(-6.0 * deltaTime));
このスケッチのフレームレートを10に落とすと、下のようになる。
フレームレートを落としたために、動きの滑らかさは無くなってしまっているけれど、だいたいの動きとしては同じになっているし、同時刻に目標座標に到達することができている(これはとても重要な性質)。
少しばかり式は複雑になったけれど、変数を追加しなくても実装できるというお手軽さは変わらない。即席的に動きを改良したくなった場合におすすめできる方法だ。