【enchant.js】神経衰弱の作り方 その2【TCard.js】
『神経衰弱の作り方 その2』です。
今回はゲームを繰り返しプレイできるよう、ループを仕込みたいと思います。
1.ループ部分の切り出し
さて。
今回はゲームを繰り返しプレイできるように変更しましょう。
まずはゲームの流れを再び見てみます。
0.カードの準備
1.カードを場に広げる
2.カードの選択
2-1.1枚目のカードを選択
2-2.2枚目のカードを選択
3.判定
3-1.同じ数なら場からのぞいて得点札に
3-2.異なる数ならカードを裏返す
4.終了判定
4-1.場にカードがないなら終了
4-2.場にカードが有るなら2に戻る
このうち『0.カードの準備』はカードのグラフィックが使えるよう、ゲームのassetsに登録する作業でした。この部分は繰り返し行う必要はありません。ゲームの繰り返しの対称となるのは1~4の部分となります。
それでは1~4の部分を切り出してみましょう。
TGame = Class.create(Scene, { initialize : function() { Scene.call(this); // enchant.TCard.setPack(); より後の行をすべてコピー }, });
切り出す際は以下の点に注意して下さい。
・Sceneのインスタンス
game.onload中のSceneのインスタンスはgame.rootSceneでしたが、Sceneクラスに切り出したことでSceneのインスタンスがthisに変わりますのでご注意下さい。game.onload中ではインスタンス名が長かったのでsceneという変数に入れていたので
var scene = this;
と記述すると変更量が少なく楽かと思います。
・assets
game.assetsはgame変数が有効なスコープ内でしか利用できませんので、ここは長いですが『enchant.Core.instance.assets』と書き換えて下さい。
clear.image = enchant.Core.instance.assets["clear.png"];
それではgame.onloadを以下のように書き換えて実行してみましょう。
game.onload = function(){ // カードの画像を assets に登録します enchant.TCard.setPack(); game.replaceScene(new TGame()); };
問題なく動きますね。
2.ループの準備
もう一度ゲームの流れに注目してみます。
0.カードの準備
1.カードを場に広げる
2.カードの選択
2-1.1枚目のカードを選択
2-2.2枚目のカードを選択
3.判定
3-1.同じ数なら場からのぞいて得点札に
3-2.異なる数ならカードを裏返す
4.終了判定
4-1.場にカードがないなら終了
4-2.場にカードが有るなら2に戻る
『1.カードを場に広げる』は1ゲームに付き1回実行される処理です。言ってみればゲームの初期化部分ですね。それでは『1.カードを場に広げる』を関数という形で切り出してみましょう――と行きたいところですが、実はそうは問屋がおろしません。2~3の処理はゲームとしては中核の部分になりますが、プログラムとしては「こうした振る舞いをしてね」ということを記述する宣言部分となります。つまり、2~3も初期化の一部になるわけなんですね。
ではここでコードを見返してみましょう。
書かれているコードはすべてdeck変数にからむものですよね? lenやmapという変数はdeckのメンバではありませんが、deckに関わることには変わりありません。つまり、1ゲームにつき1つのdeckを使うようにすれば簡単にループが実現できるわけです。
それでは、まずはinitializeの後ろにinitGameという関数を作りましょう。『Scene.call(this);』よりあとをカット&ペーストでinitGameの中に移します。
TGame = Class.create(Scene, { initialize : function() { Scene.call(this); }, initGame : function() { var scene = this; // 後略 } });
次にゲームクリア時のclear.pngのaddChild先をdeckに変更します。deckはselfで定義されているのでそれを使いましょう。
var clear = new Sprite(270, 48); clear.image = game.assets["clear.png"]; clear.x = 25; clear.y = 140; self.addChild(clear);
お次は画面全体を覆うpadというEntityをclearの後にaddChildし、Sceneにタッチされた旨を通知する処理を追加します。
var pad = new Entity(); pad.width = pad.height = 320; pad.addEventListener(Event.TOUCH_START, function() { scene.dispatchEvent(new Event("touch_clear")); }); self.addChild(pad);
最後にpadがタッチされた際の処理を追加します。
TGame = Class.create(Scene, { initialize : function() { Scene.call(this); this.addEventListener("touch_clear", this.touchClear ); this.initGame(); }, initGame : function() { var scene = this; // 略 }, touchClear : function() { console.log("クリアしました。"); } });
これで、クリアした時に画面をタッチすると次のゲームの初期化処理を行う準備が整いました。padの処理はclearにまとめてもよかったのですが、そうすると270*48の領域をタッチしないといけなくなるので画面全体を覆うEntityを使うことにしました。
3.ループの作成
それではtouchClearの中を充実させていきましょう。
まずはSceneの子となっているdeckを開放します。そしてゲームを開始するためのinitGameを呼びます。
touchClear : function() { var deck = this.firstChild; this.removeChild(deck); while (0 < deck.childNodes.length) { deck.removeChild(deck.firstChild); } this.initGame(); }
deckをSceneからremoveChildする他、deckの子についても開放するようにしました。
これでゲームのループが完成し、繰り返し遊べるようになりました。今回の通しのコードはこちらになります。
ですが、正直このコードはあまりお行儀のよいものではありません。何故かと言うと、Spriteの生成と破棄を大量にやっているからです。Spriteは生成すればその分メモリを消費します。使われたメモリはSpriteが不要となった時点で開放してやればいいのですが、その処理はブラウザに依存しておりプログラマーが制御できるものではありません(でしたよね?)。ですので、Sprite等は極力使い回した方が好ましいのです。
そんなわけで、次回はSpriteを使いまわす方向に神経衰弱を改造していきたいと思います。