前のエントリで紹介した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 件のコメント:
コメントを投稿