「Nodeをフェードイン・フェードアウトさせるしくみ」を開発するにあたって、 まずは、「ある対象ノードに対してフレームごとに何らかの処理を実行させるしくみ」を作ってみます。
対象となるノードとして、Spriteではなく、GroupやSceneを与えても、ちゃんと動作させることが目的です。 現在のenchant.jsでのGroupやSceneのオブジェクトは、階層的なひとまとまりのHTML要素ではないので、 単なるjQueryによるアニメーション指定などでは、うまく動かないのです。fpsがうまく合わないと、 画面がちらつく原因にもなります。
なお、ひとつのNodeに対して、たとえばフェードインとフェードアウトが同時に実行されるのを許してしまうと、 画面がちらついたり、悪くすれば無限ループに陥ってしまうようなことがあるかもしれません。 そこで、たとえばフェードイン処理が最後まで完了してから、 次のフェードアウト処理が開始されるというように、 処理をキューに格納して順次実行するような仕組みを作ることにします。
具体的には、以下のようになります。
enchant.effect = { }; /** * ある対象ノードに対してフレームごとの処理をするしくみ */ enchant.effect.Action = enchant.Class.create({ /** * フレームごとの処理 * @param {Node} taregtNode 対象となるノード * @param {Function} tickFunc フレームごとに実行される関数 */ initialize: function(targetNode, tickFunc){ this.targetNode = targetNode; this.tickFunc = tickFunc; this.frame = 0; if(! targetNode.queue){ //対象となるノードにキューがなければ作る targetNode.queue = []; targetNode.addEventListener('enterframe', function(){ //フレームごとの処理 if(targetNode.queue &&0 < targetNode.queue.length){ //キューが空でなければ最初のアクションを実行 targetNode.queue[0].tick(); }else{ //キューが空ならフレームごとの処理を終了 targetNode.removeEventListener('enterframe', arguments.callee); delete targetNode.queue; } }); } // キューに自身を登録する targetNode.queue.push(this); }, /** * フレームごとの処理 */ tick: function(){ this.tickFunc(this); this.frame++; } });
次に、上記のコードを利用しつつ、指定したノードについて フェードイン・フェードアウトをするしくみを実現します。
/** * ノードとその子ノードに対して、透明度を設定する */ enchant.effect.setOpacity = function(targetNode, opacity){ if(targetNode instanceof Entity){ targetNode.opacity = opacity; } if(targetNode.childNodes){ for (var i = 0, len = targetNode.childNodes.length; i < len; i++) { var node = targetNode.childNodes[i]; setOpacity(node, opacity); } } }; /** * ノードとその子ノードに対して、徐々に透明度を変化させる * @param {Node} taregtNode 対象となるノード * @param {Number} from 透明度の初期値 * @param {Number} to 透明度の最終値 * @param {Number} time 透明度変化の所要フレーム数 * @param {Function} onEndCallback 終了時に実行される関数 */ enchant.effect.fade = function(targetNode, from, to, time, onEndCallback){ setOpacity(targetNode, from); new Action(targetNode, function(action){ if(action.frame < time){ var opacity = from + (action.frame / time) * (to - from) ; setOpacity(targetNode, opacity); }else{ setOpacity(targetNode, to); if(onEndCallback){ onEndCallback(); } targetNode.queue.shift(); } }); }; /** * フェードイン * @param {Node} taregtNode 対象となるノード * @param {Number} time 透明度変化の所要フレーム数 * @param {Function} onEndCallback 終了時に実行される関数 */ enchant.effect.fadeIn = function(targetNode, time, onEndCallback){ fade(targetNode, 0, 1, time, onEndCallback); }; /** * フェードアウト * @param {Node} taregtNode 対象となるノード * @param {Number} time 透明度変化の所要フレーム数 * @param {Function} onEndCallback 終了時に実行される関数 */ enchant.effect.fadeOut = function(targetNode, time, onEndCallback){ fade(targetNode, 1, 0, time, onEndCallback); };
jQueryによるアニメーションのプログラミングように、メソッドチェインを用いていろいろな効果を重ね合わせたり、 thenメソッドの呼び出し時の引数で、フェード処理が終了した時のコールバック関数を指定するといった書き方を できるようにするというのも、面白いかもしれませんが、ひとまずこのくらいの内容でとどめておくことにします。
0 件のコメント:
コメントを投稿