2011年3月31日木曜日

動きのイージング(前編)

プログラムで、動きをイージングさせる方法です。

イージングとは、ある一動作の時間推移に偏りを持たせて動かす手法です。
何も手を加えないと、普通は一定の速度で移動していきます。

イージングさせるとだんだん移動するスピードが減速/加速していき、摩擦や重力等の力が加わったときのような動きを見せます。



プログラムやアニメーションで物を移動させるとき、本来始点と終点だけを設定してそこまで同じ速度で移動させる"等速運動"が一般的かつ楽なので使われがちですが、イマイチ面白みがないというか…ださいと思います。個人的には。

というのも、自然界の動きは殆どが"等加速度運動"をしているから、等速運動を使った表現は機械的、不自然で安っぽい感じになってしまうんじゃないかなと。そのあたり書きだすとまた長くなりそうなので端折ります。

そんなわけでで、FlashやAEでも実装されているこの"イージング"という手法を使うと、よりメリハリの効いたリッチなモーションを組むことができると思います。早速、まずは比較対象となる等速運動を書いていきます。
void testApp::draw(){
    int x = ofGetElapsedTimeMillis()/10.0f;
    int y = ofGetHeight()/2;
    
    ofSetColor(0, 0, 255);
    ofCircle(x,y,30);
}

左から右へ、青い丸がゆっくり流れていきます。これが普通の等速運動。
ofGetElapsedTimeMillis()で、OFを起動してからの時間をミリ秒を取得しています。これを10で割っているので、1秒後には1000ミリ秒/10.0f = 100ピクセルの場所まで、一定の速度で動きます。

これをイージングさせるようにします。int x,yにそれぞれ計算させた座標を代入しているので、xの計算式をいじっていきます。
void testApp::setup(){
    ofSetFrameRate(60);
}

void testApp::draw(){
    int accel = 30;
    static int x = 0;
    x += accel;

    int y = ofGetHeight()/2;    
    ofSetColor(0, 0, 255);
    ofCircle(x,y,30);
}
staticについては、後ほど解説します
少し動きが早過ぎるかと思いますので、setup()も上のようにしてフレームレートを調整しましょう。
新しく変数accelを追加し、変数xまわりを少しいじります。

x += accel;でxの値を増加させていますが、accelの値は30で固定なのでまだ青丸は一定の速度で動きつづけています。
じゃんじゃか進みます。

void testApp::draw(){
    static int accel = 30;
    static int x = 0;
    if (accel > 0) accel--;//ここを追加して、減速させる
    x += accel;
    int y = ofGetHeight()/2;
    
    ofSetColor(0, 0, 255);
    ofCircle(x,y,30);
}

ここでaccelもstatic intに変更し、accelの値を減速させて0まで持ってこさせます。
すると青い丸が徐々に減速して、途中でピタリと止まります。これがイージングのシンプルなやり方です。
これをaccelの初期値を0,減速じゃなくaccel++;として加速してやれば、今度はどんどん加速していきどこか彼方へと飛んでいきます。

ここでaccel,x両者をstatic変数におきかえましたが、これは静的変数といって関数内で値の保持される変数を表します。

通常、関数(この中ではdraw)の中で宣言された変数は、関数外に出たらその値を放棄してしまいますが、静的変数として宣言することで、また関数が呼び出されたとき前回呼ばれていた時の値をそのまま設定することができるわけです。

上の場合、もしstatic変数として宣言しないとaccelは30,xは0のままなので、表示されるxはずっと30pixの場所で止まったままになります。staticにすれば初期値の設定も最初だけ代入されるようになります。

もちろんstaticを付けずにtestApp.hの方で宣言しても同じ結果が得られますが、ここであちこちに書くと一層サンプルが煩雑になるのと、draw以外の場所でx,accelを使う必要が無かったので今回は静的変数として宣言しておきました。


若干話しがそれましたが、こんな感じでイージング処理をすることができるわけです。
ただし、これでは少し欠点が。accelの初期値が30、1ずつ減速していったので、青丸の終点は30+29+28+…+3+2+1 = 465ピクセルの所です。すごく中途半端です。
これを例えば0スタートで、450の所に止めたいとなるとこの方法ではちょっと厄介な事になってきます。

そこで後編では二次関数を使った、汎用イージング関数を作っていきます。

0 件のコメント:

コメントを投稿