【openFrameworks】ofxTweenで連続アニメーションさせる【ofxTween】
こんばんは.1000chです.
この前ふと思いついたんですが,コード中case1,case2を簡単に切り替えたいときに
/* #case1 /*/ #case2 //*/
としておくとcase2,
//* #case1 /*/ #case2 //*/
としておくとcase1が適用でき,冒頭の/
有る無しでtoggleできます.
よく切り替えが発生する部分なら#indef
使えって話なんですけど.後々消すつもりでちょっとテストしたいなー,って時には便利...じゃないかなぁ?
さて,それとは関係なく今回もoFネタいきますよ.
ofxTweenでchainable animation
前回,ofxTweenの簡単な使い方を見ていきました. 基本は
- setParametersして
- updateする
って言う感じでしたね. ただ,コレだとTween.jsでいうような
target.alpha = 1; Tween.get(target).wait(500).to({alpha:0, visible:false}, 1000).call(handleComplete); function handleComplete() { //Tween complete }
っていう感じのメソッドチェーンがやりづらいです. てことで今回はofxTweenつかったメソッドチェーンのやり方を考えていこうと思います.
ofxTweenを読む
さてじゃーどうやるのか,って話で,ofxTweenのコードを見るしかありません. とりあえずヘッダを眺めていると..
public: // 中略 ofEvent<int> end_E;
なんてのがいるじゃないですか. 察するにtween終了時に発火されるイベントである予感がします.
tweenを進めているのはupdate
メソッドなので,そいつをのぞいてみます.
//ofxTween.cppより抜粋. line170~ float ofxTween::update() { if(!completed){ // まだtweenが終わってないなら if(frameBased){ //フレームベースのtween(今回関係ないのでコメント割愛) ofxEasingArgs args; elapsed++; args.t= elapsed; args.d= float(duration); for(unsigned i=0; i<from.size(); i++){ args.b=from[i]; args.c=change[i]; easingFunction->notify(this,args); pTarget[i] = args.res; } if(pTarget[0]==to[0]) running=false; else running = true; }else{ // timestampベースのtween // start時のtimestamp+delayから数えてduration分過ぎているか (*) if (timestamp.isElapsed(duration)){ // 各ターゲットの値を全て目的の値にセット for(unsigned i=0; i<from.size(); i++){ pTarget[i] = to[i]; } running = false; //まだtweenしているかフラグoff completed = true; //tween終わったかフラグon.以降このループは呼ばれない ofNotifyEvent(end_E,id); // ofxTween::end_Eイベント発行. 引数は自身のid. (**) } else if(timestamp.elapsed()>0){ // start時からdelay分過ぎているか ofxEasingArgs args; float elapsedTime = float(timestamp.elapsed()); args.t= elapsedTime; args.d= float(duration); for(unsigned i=0; i<from.size(); i++){ args.b=from[i]; args.c=change[i]; //現在timestampでeasingした値を計算させる easingFunction->notify(this,args); pTarget[i] = args.res; } running = true; } } } return getTarget(0); //0番目ターゲットの現在値をreturn }
ちょいちょいコメントしましたが,ポイントは中盤のtween終了ブロックです.
(*)の条件判定でtween開始時からduration分過ぎている場合にこの処理に入り,
各種フラグを設定したのち,(**)でofNotifyEvent
しています.思った通りです.
ここのイベント発行はofEvent<int> end_E
とあるようにint型引数をわたします.
でソレが何かというと,ofxTween::setParameters
で指定したid,というわけです.
(注:同一tween内のpositionとは関係無い)
idって何に使うのか,と思ってたのですが,要するにどのtweenが終了したかの識別
に使える訳ですね
(注:end_E自体は各インスタンスに固有なので,tweenAとtweenBの識別は不要です.idの使い方の例を後に紹介します).
とまぁココまでわかったことをまとめると
- tween終了時に各インスタンスが持つ
ofxTween::end_E
イベントが発火される ofxTween::setParameters
で指定したidが引数として渡される
ここまでわかってしまえば,いつぞや書いた記事で紹介したように
ofAddListener
でtween終了時のコールバックを設定することができそうです.
連続したtweenアニメーションをつくる
では,いよいよ連続したtweenアニメーションを作ってみましょう.
一つのofxTweenインスタンスを生成し,ofRectのx,yをそれぞれtweenさせます(複数値tweenに関しては前回記事参照).
# ofApp.h #pragma once #include "ofMain.h" #include "ofxTween.h" class ofApp : public ofBaseApp{ public: void setup(); void update(); void draw(); void keyPressed(int key); void keyReleased(int key); void mouseMoved(int x, int y ); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); void mouseReleased(int x, int y, int button); void windowResized(int w, int h); void dragEvent(ofDragInfo dragInfo); void gotMessage(ofMessage msg); ofxTween my_tween; ofxEasingBounce easing_bounce; ofxEasingBack easing_back; ofxEasingLinear easing_linear; ofxEasingSine easing_sine; void tweenCallback(int &e); };
// ofApp.cpp #include "ofApp.h" void ofApp::setup(){ ofSetRectMode(OF_RECTMODE_CENTER); ofBackground(0); // ダミー,変化しないtween my_tween.setParameters(0, easing_bounce, ofxTween::easeIn, 100, 100, 1000, 0); my_tween.addValue(100,100); // point-1 ofAddListener(my_tween.end_E, this, &ofApp::tweenCallback); } void ofApp::update(){ my_tween.update(); } void ofApp::draw(){ ofRect(my_tween.getTarget(0), my_tween.getTarget(1), 50, 50); } void ofApp::mousePressed(int x, int y, int button){ my_tween.setParameters(1, easing_bounce, ofxTween::easeOut, 100, 800, 1000, 0); my_tween.addValue(100, 100); } void ofApp::tweenCallback(int &e){ // point- 2 switch (e) { case 1: my_tween.setParameters(2, easing_back, ofxTween::easeOut, 800, 800, 1000, 500); my_tween.addValue(100, 600); break; case 2: my_tween.setParameters(3, easing_linear, ofxTween::easeIn, 800, 300, 1000, 500); my_tween.addValue(600, 600); break; case 3: my_tween.setParameters(4, easing_sine, ofxTween::easeInOut, 300, 100, 1000, 300); my_tween.addValue(600, 100); break; case 4: my_tween.setParameters(1, easing_bounce, ofxTween::easeOut, 100, 800, 1000, 500); my_tween.addValue(100, 100); break; default: break; } }
順に解説します.
ポイントの1点目は,生成したtweenのend_E
イベントをlistenしている点(point-1).
ofAppクラス内に,tweenが終了したら次のtweenを発動させる処理を書き,これをコールバックとして登録します.今回はtweenCallback
というヤツですね.
ポイントの2点目は,tweenCallback内部の処理です.
先述したように,end_E
イベントのコールバックにはsetParameters
で指定したidが渡されます.
setParameters
で与えるidは自由な値を使えるので,この値を利用して今どのtweenが終了したのかを識別出来ます.
そこで,わたされるid(コールバック引数的にはint &e
)をswitch文でルーティングすることで,次に実行するtweenを切り替えることが出来ます.
今回は「1がおわったら2,2が終わったら3,..4が終わったら1に戻る」という形にしてみました.
これにより,「最初は右にいって,つぎに下に動いて,その後左に動いて..」という処理が可能となります.
もちろん各setParameters
ではduration,delay,easing
等個別で設定できますので,
1-2間はゆっくり変化させる,3-4間には少しdelayを入れる,等も自由自在ですね.
なお今回,プログラム起動時はid=0として動かないtweenを指定してあります.
mousePressed
が呼ばれた時にid=1のtweenがsetされる形ですね.
動かすとこんな感じです.
いかがでしょうか.連続アニメーションっぽくできてるのではないでしょうか.
この例のようにループさせるのであればupdate内でflagつくって管理とかもできますが, ループさせない場合,例えば「クリックされたときに一旦右に行って,次に左に行って止まる」みたいな一回動かすだけだけど,ちょっと複雑みたいな場合には使えるんじゃないかな.
まとめ
- ofxTweenちょこっと読んでみた
- ofxTweenつかった連続アニメーションをつくってみた