前のエントリで紹介したNodeのフェードイン・アウト機能を利用しつつ、 enchant.js に標準添付されているプラグイン nineleap.enchant.js を拡張して、次の機能を実現するプラグインを作成します。
- 「START」「GAME OVER」をフェードイン・アウトによるトランジション効果を利用して表示する
- ローカル環境での実行時に、「GAME OVER」画面をタッチ・キーダウンすると「もう一度プレイ」できるようにする
これを、nineleap_fade.enchant.js というファイル名で作成するものとします。 なお、この開発にあたっては、次の点に注意しました。
- nineleap.enchant.jsは修正しない。
- ゲーム本体のプログラム(game.js)の修正は、最小限にとどめる。
というわけで、以下、これを実現するコードです。
/** * ローカル環境でのデバッグ時に、ゲームオーバー画面のクリックまたはキーダウンで * 「もう一度プレイする」を可能にするためには、この値をtrueにする。 * nineleapに投稿する際にはtrueにしておく。 */ var NINELEAP_RELEASE_MODE = false; var START_IMAGE = 'start.png'; var END_IMAGE = 'end.png'; enchant.nineleap_fade = {}; enchant.nineleap_fade.Game = enchant.Class.create(enchant.nineleap.Game, { initialize: function(width, height) { enchant.nineleap.Game.call(this, width, height); this.sceneTransition = false; this.overwriteLoadEventListener(); }, // enchant.nineleap.Gameにおけるloadイベントリスナを解除・上書き overwriteLoadEventListener: function(){ this._listeners['load'] = []; this.addEventListener('load', function() { this.startScene = new SplashScene(); this.startScene.id = 'startScene'; this.startScene.image = this.assets[START_IMAGE]; this.pushScene(this.startScene); fadeIn(this.startScene, 10); this.endScene = new SplashScene(); this.endScene.id = 'endScene'; this.endScene.image = this.assets[END_IMAGE]; this.addTransitionEventListeners(); }); }, // トランジションのためのイベントリスナを登録 addTransitionEventListeners: function(){ var game = this; this.startScene.addEventListener('touchend', function() { game.startScene.removeEventListener('touchend', arguments.callee); if (game.started == false && game.sceneTransition == false) { game.sceneTransition = true; if (game.onstart != null) game.onstart(); game.onGameStartTouched(); } }); this.endScene.addEventListener('touchend', function(){ if(game.sceneTransition == false){ game.sceneTransition = true; game.endScene.removeEventListener('touched', arguments.callee); game.onGameEndTouched();//fadeout endScnene and popScene } }); this.addEventListener('keydown', function() { if (game.currentScene == game.startScene && game.sceneTransition == false){ game.sceneTransition = true; game.removeEventListener('keydown', arguments.callee); if (game.started == false) { if(game.onstart != null) game.onstart(); game.onGameStartTouched();//fadeout startScnene and popScene } } }); this.addEventListener('keydown', function() { if (game.currentScene == game.endScene && game.sceneTransition == false){ game.sceneTransition = true; game.removeEventListener('keydown', arguments.callee); game.onGameEndTouched();//fadeout endScnene and popScene } }); }, //ユーザによるゲーム開始画面のタッチ後に実行される関数, onGameStartTouched: function(callback){ var game = this; game.started = true; gameStart = true; // deprecated fadeOut(game.startScene, 10, function(){ if(game.currentScene == game.startScene){ game.popScene(); } if(callback){ callback(); } game.sceneTransition = false; }); }, //ゲームオーバーのときの終了処理を実行する end: function(score, message){ this.started = false; enchant.nineleap.Game.prototype.end.call(this, score, message); fadeIn(this.endScene, 10); }, //ユーザによるゲーム終了画面のタッチ後に実行される関数 onGameEndTouched: function(callback){ var game = this; gameStart = false; // deprecated fadeOut(game.endScene, 10, function(){ if(game.currentScene == game.endScene){ game.popScene(); } }); if(NINELEAP_RELEASE_MODE){ return; } fadeOut(game.getGameNode(), 10, function(){ if(game.reset){ game.reset(); } fadeIn(game.getGameNode(), 10, function(){ game.pushScene(game.startScene); fadeIn(game.startScene, 10, function(){ game.addTransitionEventListeners(); if(callback){ callback(); } game.sceneTransition = false; }); }); }); }, /** * ゲーム終了・リセット再開時に、 * フェイドイン・フェイドアウトされるゲーム画面のnodeを返す関数。 * デフォルトではgame.rootSceneを返すので、開発者側で必要に応じて * game.getGameNode = function(){ return fooScene };のように定義して * おくことで内部的に呼び出される。 */ getGameNode: function(){ return this.rootScene; }, /** * NINELEAP_RELEASE_MODE==falseのときに、自前でゲームを再開するための、 * 各種ゲーム状態(スコア・自機位置・敵位置など)の初期化処理を記述するための関数。 * game.reset = function(){....}; のように定義しておくことで内部的に呼び出される。 */ reset: function(){ alert("reset関数を実装してください"); } });
以下、使い方です。
- 開発者は、この冒頭の NINELEAP_RELEASE_MODE 定数を、 9leapに投稿時には true に、ローカルでデバッグしたり遊んだりするときには false に しておく必要があります。
- Gameをインスタンス化した後に、そのメンバとして getGameNode関数と、reset関数を上書き再定義しておく必要があります。
- ゲームオーバー時なには、game.started変数をfalseにセットする必要があります。
- ゲーム終了時・再開時の「ゲーム画面は見えているが、プレイすることができない瞬間」を実現するために、 enterframeのイベントリスナの関数内の処理の冒頭で、game.started変数をチェックして、以降の処理をキャンセルする コードを必要に応じて追加する必要があります。
- ゲームの実行時に登録したイベントリスナは、不要になった時点で削除してください。たとえば、 this.removeEventListener('enterframe', arguments.callee); のようなコードを 適切な箇所で実行してください。余計なイベントリスナが残っていると、ゲームを「もう一度プレイ」する際、 イベントリスナの登録が多重的に実行されてしまい、ゲームが正常に動作しなくなることがあります。
たとえば、enchant.jsのサンプルである、examples/action/game.jsにおいて、 この nineleap_fade.enchant.js を適用するならば、次のような修正をすることになります。
*** examples/action/game.js 2012-01-11 03:47:36.000000000 +0900 --- examples/action/game_fade.js 2012-01-20 21:47:17.000000000 +0900 *************** *** 62,68 **** --- 62,85 ---- bear.jumping = true; bear.jumpBoost = 0; bear.image = game.assets['chara1.gif']; + + game.reset = function(){ + bear.x = 8; + bear.y = -32; + bear.vx = 0; + bear.vy = 0; + bear.ax = 0; + bear.ay = 0; + bear.pose = 0; + bear.jumping = true; + bear.jumpBoost = 0; + stage.x = 0; + }; + bear.addEventListener('enterframe', function(e) { + if(game.started == false){ + return; + } var friction = 0; if (this.vx > 0.3) { friction = -0.3; *************** *** 162,167 **** --- 179,185 ---- this.y = dest.y-2; if (this.y > 320) { + game.started = false; game.assets['gameover.wav'].play(); var score = Math.round(bear.x); this.frame = 3; *************** *** 171,185 **** this.y += Math.min(Math.max(this.vy, -10), 10); if (this.y > 320) { game.end(score, score + 'mで死にました'); } }); - this.removeEventListener('enterframe', arguments.callee); } }); ! var stage = new Group(); stage.addChild(map); stage.addChild(bear); stage.addEventListener('enterframe', function(e) { if (this.x > 64 - bear.x) { this.x = 64 - bear.x; } --- 189,206 ---- this.y += Math.min(Math.max(this.vy, -10), 10); if (this.y > 320) { game.end(score, score + 'mで死にました'); + this.removeEventListener('enterframe', arguments.callee); } }); } }); ! stage = new Group(); stage.addChild(map); stage.addChild(bear); stage.addEventListener('enterframe', function(e) { + if(game.started == false){ + return; + } if (this.x > 64 - bear.x) { this.x = 64 - bear.x; }
0 件のコメント:
コメントを投稿