昔作ったゲームをJSっぽくリファクタリングした結果【tmlib.js】

# はじめに
* 同期的な書き方を減らそうと頑張った痕跡をメモった記事です。
* 私はゲーム設計に関して右も左も分からない人間です。
* クソコードで恥ずかしいですが勇気を出して。

# tmlibで昔さくっと作ったゲーム
![ss2.png](https://qiita-image-store.s3.amazonaws.com/0/59549/c6c5e440-388c-489c-3e2a-d11aac8d767a.png)

* [Wave Fever (jsdoit)](http://jsdo.it/Akihiro.Yamamoto/9ckf)
* [github](https://github.com/varmil/try_tmlib)
* ネイティブで出ていた「Wave Weaver」をリバエンしたゲームです。

# 早速Before-Afterいきましょ

## Before (Game Sceneのみ)
```js:before
tm.define("GameScene", {
	superClass: "tm.app.Scene",
	pattern: null, // Patternインスタンス
	level: 0, // ゲームレベル(初回０。徐々に上がる)
	
	init: function() {
.....
		window.player = Player().addChildTo(this);

		this.timer = Timer().addChildTo(this);
		this.levelLabel = levelLabel().addChildTo(this);
		
		// 初回パターン生成
		this.createPattern(this);
	},

	update: function(app) {
		// 一連のパターンが判定終了したら、インターバルを置いた後、次のパターンへ。
		if (this.pattern && this.pattern.ended_flag) {
			this.pattern = null;
			setTimeout(this.createPattern, NEXT_PATTERN_INTERVAL, this);
		}

		// 一定時間毎にレベルアップ
		if (this.timer.label.text > this.level * 15 + 15) {
			this.level = this.level + 1;
			this.levelLabel.levelUp(this.level);
		}

		// ゲームオーバーチェック
		if (window.player.playerIcon.isDead){
			// 間違った色に接触した瞬間にタイマーをストップする
			this.timer.sleep();
		}
		if (window.player.playerIcon.isGameOver){
			app.replaceScene(GameOverScene(this.level, this.timer.label.text));
		}
	},

	createPattern: function(obj) {
		obj.pattern = Pattern(obj.level).addChildTo(obj);
	}
});
```

## After (Game Sceneのみ)
```js:after
tm.define("GameScene", {
	superClass: "tm.app.Scene",
	level: 0, // ゲームレベル(初回０。徐々に上がる)

	init: function() {
.....
		window.player = Player().addChildTo(this);
		player.playerIcon.on('collision', function() {
			player.playerIcon.off('collision');
			self.timer.off('levelUp');
			// 間違った色に接触した瞬間にタイマーをストップし、レベルアップカウントも停止
			self.timer.sleep();
			clearInterval(self.timer.intervalID);
		});
		player.playerIcon.on('dieAnimationEnd', function(e) {
			player.playerIcon.off('dieAnimationEnd');
			self.app.replaceScene(GameOverScene(self.level, self.timer.label.text));
		});

		this.timer = Timer().addChildTo(this).on('levelUp', function() {
			self.level = self.level + 1;
			self.levelLabel.levelUp(self.level);
		});

		this.levelLabel = levelLabel().addChildTo(this);

		this.pattern = Pattern().addChildTo(this).on('popEnd', function(e) {
			// 一連のパターンが終了したら、インターバルを置いた後、次のパターンへ。
			setTimeout(_.bind(self.createPattern, self), NEXT_PATTERN_INTERVAL);
		});

		// 初回パターン生成
		this.createPattern();
	},

	update: function(app) {
		/* nothing to do */
	},

	createPattern: function() {
		var patternNum  = tm.util.Random.randint(0, 2);
		var popPosition = tm.util.Random.randint(POP_POS_LEFT, POP_POS_RIGHT);

		switch(patternNum){
			case PATTERN_NORMAL:
				this.pattern.createNormal(this.level, popPosition);
				break;
			case PATTERN_NARROW:
				this.pattern.createNarrow(this.level, popPosition);
				break;
			case PATTERN_RUSH:
				this.pattern.createRush(this.level, popPosition);
				break;
		}
	}
});
```

# 何が変わったのか
* Playerクラスのgameoverに関する処理をイベント駆動っぽくした。（以前は `update()` を使ったかなり同期的な書き方になっていた。）
* Patternクラスのインスタンス生成を1度だけにして、こちらもイベント駆動っぽい書き方に直した。
* 参考： [[tmlib.js]tmlibで学ぶ、イベント駆動型のクラス設計](http://qiita.com/omatoro/items/ce5a21596ba5a5745fc0)
* 追記： Timerもイベント駆動にして、遂に `update()` を空に出来ました。やった。

# 無知は罪である
* このゲームを作っていた際は、Beforeのような同期的な書き方しか知らなかった。フラグを大量に使う書き方しか知らなかった。
* それから数ヶ月、相対的に少しは見るに堪える書き方が出来つつあるのではないか。 ~~timer部分もupdate()から外に出したい。~~ (済)。出来ればフラグ数を0にしたい。クラスのプロパティもより減らしたい。

# おわりに
* Afterもクソな部分ばかりです、多分。ので、間違いや改善案があった際はご指摘頂けると幸いです。
* 設計は本当に難しい。まとまった情報が欲しい。