動的迷路でドットイートゲームを作る(1)の続きです。今回はGameクラスを実装してゲームを完成させます。

Gameクラスの定義

Game全体の進行を管理するためのGameクラスを定義します。

コンストラクタ

最初にコンストラクタを示します。

Vertexオブジェクトの初期化

Vertexオブジェクトを生成します。また行番号と列番号からオブジェクトを取得できるようにGetVertexByRowCol関数も定義しておきます。

Edgeオブジェクトの初期化

Edgeオブジェクトを生成します。また辺の両端の頂点の行番号と列番号からオブジェクトを取得できるようにGetEdgeByRowCol関数も定義しておきます。

迷路を生成する

迷路を生成する処理を示します。

各辺の重みとして乱数を割り当て、これをもとに最小全域木を構築します。ただし迷路生成時のタイミングで辺をわたっているキャラが存在する場合、辺がなくなってしまうと困った問題がおきます。そこでそのような辺が存在する場合は重みを 0(最小値)にして必ず辺が存在するようにします。

あとは辺を重みでソートして閉路ができないように辺の重みが小さいものからつないでいきます。閉路ができるかどうかはUnionFind木で判定することができます。辺をつないだら両端の頂点を同じグループにすることで、同じグループに属するかどうかを調べることで閉路ができるかどうかがわかります。

最小全域木を構築すると必ず葉ができます。迷路において葉とは行き止まりとなる部分です。行き止まりの部分ができないように葉は隣にある頂点と適当につないで行き止まりを解消します。

ゲーム開始の処理

ゲーム開始時の処理を示します。

自機の移動

移動処理に関する関数を示します。

GetVertexByPosition関数は指定された座標と一致するVertexオブジェクトを返します。完全に一致したものがない場合はnullを返します。これによって現在位置が方向転換可能地点かどうかがわかります。

GetEdgeByPosition関数は指定された座標に対応するEdgeオブジェクトを返します。これはnullを返すことはありません。これによってキャラが現在通行中の辺がどれなのかがわかります。

CanMove関数は指定された座標から指定された方向に移動可能なのかを返します。指定方向に1ピクセルずらした座標は通行可能な辺なのかを調べています。

SetPlayerDirct関数は自機が次に方向転換可能点に来たら方向転換する方向を設定します。

MovePlayer関数は自機を移動させる関数です。

ステージクリア

CheckStageClear関数はステージクリアしたかどうかを調べ、ステージクリアしているときはボーナスポイントを加算して次のステージに移行します。

敵の移動

敵を移動させる処理を示します。

最初に各敵の移動方向を決めます。その敵が方向転換可能地点にいなければなにもしません。

4つの敵が自機めがけて一斉突撃してくるとゲームにならないので乱数でバラします。一番かしこい(?)のが赤い敵で一番マヌケな敵がオレンジの敵です。

移動方向の候補を格納する配列を宣言して、一定確率で自機にむけて移動可能であればその方向を配列に格納します。

この方法だと候補となるものが存在しない場合がありえます。この場合は移動可能な方向をすべて配列に格納します。最後に候補が複数ある場合は乱数で適当に決めます。

移動方向が確定したらその方向に敵を移動させます。

当たり判定

当たり判定の処理を示します。自機と敵の距離を調べ、一定距離より近い場合があればミスとして扱います。

ミス時の処理

ミス時の処理を示します。

ミス時は残機を 1 減らしたあと、それでも残機が存在するときは 2 秒後に各キャラを初期位置に戻してゲームを再開します。残機が 0 になった場合はゲームオーバー処理をおこないます。この一連の処理が完了するまで各キャラの移動は停止します。

更新と描画

更新と描画に関する処理を示します。

更新は16msおき(1秒間に60回)におこないます。これは前回更新時刻を記録しておけば実現できます。

更新時は各キャラの移動処理と当たり判定をするのですが、それとは別に迷路の変更処理も必要です。迷路を変更する時刻になったら迷路を変更する処理をおこないます。

描画処理をしめします。

スコアランキングへの登録

スコアランキングに登録する処理をしめします。

サーバー側の処理とスコアランキングを表示させる処理はゲーム開始以降の処理 鳩でもわかるXORパズルをつくる(2)と同じなので省略します。

ページが読み込まれたときの処理

ページが読み込まれたときの処理を示します。

Gameオブジェクトを生成してキー操作やボタンの押下に対応できるようにイベントリスナを追加します。そのあと更新処理を開始します。

レンジスライダーでボリューム調整ができるようにする処理はいつもどおりです。