「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 件のコメント:
コメントを投稿