Motion 7, 加速度のコントロール

Nov 20, 2010

さて、これまで紹介した動きはいわゆる等速運動、一定の速度で動く動きです。 次からは、加速・減速の動きのバリエーションを紹介します。
例えば、ボールを放ったときの動きを表現するとします。放られたボールは最初は勢いよく、やがて動きをゆるめて地面に落ちます。
X軸(横移動)に絞って色々試してみます。

これまでの例では、x += speed というステートメントで表現されるような、一定量の座標が加算される動きでした。

var x = 0, speed = 10; // 横座標, 速度
...
x += speed;

速度を徐々にゆるめたいときもっとも単純なのは、速度を減算で減らすという方法です。

const DECELERATION = 1; // 減速
var x = 0, speed = 10; // 横座標, 速度
...
x += speed; // 速度分移動
speed -= DECELERATION; // 速度を落とす
if (speed < 0) return false; // 速度が0になったらアニメーション終了

しかしこの方法だと、到達位置が成り行きになってしまいます。それはそれでいいのですが、例えば到達位置ありきの動きにしたい場合、これだと計算がややこしくなります。そこで考えられるのが、現在位置と到達位置の間隔を割り算で削る方法です。

const START_X = 0, END_X = 100, DECELERATION = .8; // 開始・終了座標, 減速
var x, distance = END_X - START_X; // 横座標, 間隔距離
...
distance *= DECELERATION; // 間隔を割り算する
x = END_X - distance; // 終了座標から間隔を差し引いて現在座標を計算
if (distance < 0.1) return false; // 間隔がほぼ0になったらアニメーション終了

しかしこの方法にはちょっと問題があります。いわゆるアキレスと亀の問題で、間隔が無限に縮まるだけで決して到達位置になる事はありません。従って、ほぼほぼ到達位置になったらアニメーションを止める、という処理が必要になるかもしれません。また到達位置に近づくにつれ、動きは極端にゆっくりになります。

三角関数で表現しようとするとちょっと複雑です。
サインは、0°から90°(0.5π)に移るあいだに、0から1まで丸みのある数字(最初にグンと増え、1に近づくにつれゆるくなる)を出します。この性質を利用して、角度を時間、サインの値を距離に置き換えて表現します。

const START_X = 0, END_X = 100, DURATION = 100; // 開始・終了座標, 継続時間
const WHOLE_RAD = Math.PI * 0.5; // 90°に相当する弧度
var elapsed, x, radian; // 経過時間、横座標, 弧度
...
radian = WHOLE_RAD * (elapsed / DURATION); // 現時刻の相対値を弧度に変換
x = Math.sin(radian) * (END_X - START_X); // 座標の計算
if (elapsed == DURATION) return false; // 経過時間が満了したらアニメーション終了
elapsed++; // 時間経過

それぞれ、実際に動かしてみます。

クリックすると動きだします

uni

sub

div

sin

uni が等速運動(uniform)、sub が引き算(subtraction)、div が割り算(division)、sin がサインでの動きです。
どの方法がよいかは状況次第だけど、動きをしっかりコントロールしたい場合は、位置と時間をきちんと把握できるサイン方式になるでしょうか。

続く:Motion 8, 弱まっていく動き


Comments