2010 02 07

テトリスを作るの7

最後のテトリス。

今日はコントローラー。 ゲームの開始と終了、キー入力の受付、時間の管理を担当する。 開始ボタンが押されたら、

フィールドから終了を報告されたら、

時間の管理は、

操作に関係無く経過時間だけで速くするか、落としたら速くするか、行を消したら速くするか。 ちょっと悩んで、行を消したら速くすることにした。 複数行を消した場合は、その行数だけ速くする。

キー入力は、左移動を H ,右移動を K ,回転を J ,落下を space にしてみた。

// コントローラー function Controller() { var self = this; var INTERVAL = { INIT : 1000, MIN : 100, DIFF : 10 }; var score = new Score(); var field = new Field( this ); var timerId = null; var interval = INTERVAL.INIT; var started = false; var movers = { 'H' : field.left, 'K' : field.right, 'J' : field.turn, ' ' : field.drop }; this.start = function () { if ( !started ) { score.init(); field.init(); document.onkeyup = function ( e ) { try { movers[ String.fromCharCode( e ? e.keyCode : event.keyCode ).toUpperCase() ](); } catch ( e ) {}; }; interval = INTERVAL.INIT; started = true; _proceed(); } }; this.stop = function () { document.onkeyup = null; document.getElementById( 'start' ).disabled = true; started = false; }; this.report = function ( deletedLines ) { score.countUp( deletedLines ); if ( ( interval -= ( INTERVAL.DIFF * deletedLines ) ) < INTERVAL.MIN ) { interval = INTERVAL.INIT; } }; function _proceed() { if ( started ) { field.down(); timerId = setTimeout( _proceed, interval ); } else { clearTimeout( timerId ); alert( "終了" ); document.getElementById( 'start' ).disabled = false; } } }

キー入力の検査で、無効なキーの判定がまた例外まかせ。

// 例外を使わない判定処理 document.onkeyup = function ( e ) { var mover = movers[ String.fromCharCode( e ? e.keyCode : event.keyCode ).toUpperCase() ]; if ( mover ) { mover(); } };

とした方がいいような気がする。 または素直に switch で。 だから、だったらそうしろよ、と。

ゲーム中フラグや開始ボタンの操作可否の設定は、ゲーム終了時の挙動を怪しくしないため。

タイマーの解除は、どうやら次の呼び出しを行わないようにするだけで、イベントキューにその時点で登録済みのイベント処理までは消さないらしい。 フィールドからの終了報告でタイマー解除して終了とすると、終了したつもりでいるその直後にタイマーの処理がちょいと動いてしまう時があるのだ。 その辺りの怪しい動きを抑えるために、タイマー処理の中でゲーム中フラグで処理を分け、タイマーの解除もここでやることにした。

最後に、画面読み込み完了イベントでの処理。 コントローラーを生成し、開始ボタンのクリックイベントでゲームを開始するように設定する。

// コントローラーの生成 window.onload = function () { var controller = new Controller(); document.getElementById( 'start' ).onclick = controller.start; };

これで一応の完成。

ところでコントローラーだが、完成したのは最後でも、仮版は最初にできてたりする。 仮版に実装しているのは、キー入力イベント関係。 ここだけでも先に作っておくと、早い段階で動きの確認ができていいんだよね。 あと、ちょっとした感動も。 ゲームにはならなくても、キーボードをポチッと押して 「おお! 動く!」 とか、 「回る! 回るぞ!」 とか。 こんなちょっとした感動が、やる気を継続するのに効果的だったりするのだ。

テストプレイをしてるうちに思い出したのだが、かつて遊んだX68000版のテトリスには 「ステージ」 が有ったんじゃなかったかな。 ステージクリアすると、少しゴミが残った状態から次のステージが始まってたような気がする。 ステージが進むと、最初のゴミも増えていたような。 テトリミノの落下は連続的にだんだん速くなるんじゃなくて、ステージ毎に離散的に速くなっていったような。

まあ、いいか。 しかし、いい世の中になったよなぁ。 メモリの節約を考えなくても平気だし、少々無駄な処理があってもそれなりの速度で動いてくれるし。 油断すると堕落の一途。 いや、もう堕ちるところまで堕ちているのかも。 「ブラウザ上のちょっとした玩具なんだから、メモリリークとか気にしなくていいじゃん」 なんて思ってるもんな。

半年後にこのコードを見たら、また全部書き直したくなるんだろう。 それはそれで楽しみ。