ASP.NET Coreの使い方をひととおり勉強したのでスコアランキングを偽装できないゲームとしてクラッシュローラーをつくりなおします。要はランキング機能を追加する JavaScriptでクラッシュローラーをつくる(6)の作り直しです。

まず通路がどのようになっているかを管理するためのテキストファイルを作成します。これはJavaScript版クラッシュローラーを作成するときにつくったjsファイルを元につくります。内容は数値とカンマだけテキストです。ここからダウンロード可能です。

Road列挙体とDirect列挙体

まず通路と移動方向を管理するための列挙体を示します。

Gameクラスの作成

次にゲームを管理するGameクラスを作成します。CrashRollerという名前空間を定義し、そのなかにGameというクラスを定義します。

名前空間を書いてしまうとインデントが深くなるので以降は省略します。

またGameクラス内ではEnemyクラス、Rollerクラスのインスタンスが生成されていますが、これは次回示します。実はC# WindowsFormsでクラッシュローラーを作成したときの敵に追尾させ挟み撃ちさせる ローラーで敵を踏みつぶすに書かれているものとほとんど同じです。

定数とフィールド変数

最初に定数とフィールド変数を示します。

プロパティ

次にプロパティを示します。外部からは変更されることなく取得することのみを可能にしています。

初期化

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

マップは作成したらそれを使い回せるので1回だけ作成します。MapHeightが0以外であればすでに作成されていることになります。そのあとプレイヤーと敵とローラーを初期化し、タイマーをセットします。

マップを初期化する処理を示します。リソースに最初に示したテキストファイルを追加しておいてそれを読み込んで処理をします。

プレイヤーと敵を初期化する処理を示します。外部から座標を取得できるようにするために初期化したら座標をプロパティにセットします。

ローラーを初期化する処理を示します。これも外部から座標を取得できるように初期化したら座標をプロパティにセットしておきます。

タイマーを初期化する処理を示します。タイマーは同じものを使いますが、イベントハンドラは別に設定します。ユーザーがページから離脱したらイベントハンドラを取り除くことができるようにフィールド変数に保存しておきます。

ゲームオブジェクトが不要になったときの処理を示します。バックアップしておいたタイマーのイベントハンドラを取り除きます。

ゲーム開始の処理

ゲームを開始するための処理を示します。

ゲームオーバーになってからサイドゲーム開始の処理がおこなわれるかもしれないのでプレイヤーと敵、スコアなどを初期化しています。そしてクライアントサイドでも処理をおこなえるようにイベントを発生させて通知できるようにしています。

プレイヤーの移動処理

以下は各キャラクタの移動をおこなううえでそれが二次元配列の範囲内にあるかどうかを調べるためのメソッドです。

プレイヤーを移動する処理を示します。

後述するSetPlayerDirectメソッドでキーが押されているかどうかで移動方向をセットします。そのあとPlayerDirectプロパティに応じてプレイヤーの座標を移動させます。

このときローラーを使用しているときはローラーも移動させます。そしてこれまで通路のうち通過していない部分を通過したらスコアを追加します。

キーが押されているかどうかで移動方向をPlayerDirectプロパティにセットする処理を示します。

ローラー使用時は方向転換不可なのでIsHoldRollerXプロパティを調べて状況によってはそのままreturnしています。通路と橋が交差する部分では通路から橋に乗り入れることができるバグを避けるため、このような場合は方向転換できないようにしています。

ローラーを移動させる処理を示します。

ローラーの可動範囲でローラーを押すことができる位置にプレイヤーが存在する場合はローラーを移動させています。またどの方向にローラーが移動しているのかがクライアントサイドでもわかるようにIsHoldRollerXプロパティをセットしています。

当たり判定

当たり判定の処理を示します。

プレイヤーと敵が重なっている場合、ローラーを使用している場合は敵を倒したときの処理をおこない、そうでない場合はミスの処理をおこないます。このとき近い距離にいても一方が橋のうえで他方がそうではない場所にいる場合は当たり判定はfalseになるように注意します。

敵を倒したときとミス時の処理

敵を倒したときの処理を示します。

敵を倒したら2秒間ゲームの動作を停止させます。そしてクライアントサイドで倒した敵の近くに加算される点数を表示するため、その座標をPositionHitEmemyプロパティにセットしています。そのあとイベントを発生させてクライアントサイドで適切な処理ができるようにしています。

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

ミス時は2秒間ゲームの動作を停止させます。残機を1減らし敵を倒したときに加算される点数をリセットします。そしてクライアントサイドで残機の表示数を減らすためにイベントを発生させています。

ゲームオーバー時の処理を示します。IsGamingプロパティをfalseにして動作を停止させます。これによってゲームスタートの処理ができるようになります。

クライアントサイドでゲームオーバー時の効果音を鳴らす処理をおこないたいので、この場合もイベントを発生させます。

ステージクリアの処理

これまで通過していない座標を通過したら加点する処理を示します。

10点を加算しますが、加点の頻度を下げるため4回に1回の割合とします。またこれまで通過していない座標を通過した場合はその座標をEatXプロパティとEatYプロパティにセットします。クライアントサイドでこの座標を取得して通路の表示色を変更できるようにしています。

ステージクリアしているかどうか調べる処理を示します。

通過した部分は色を変更しますが、これだと通過していない点が存在してもすでに色が変わっているため未通過であることにユーザーは気づくことができません。そこで通路のすべての部分の色が変更されている場合はステージクリアと判定できるように、未通過の座標が存在しても近くにすでに通過している点が存在する場合は通過済みとして扱います。

これで未通過の点が存在しない場合はステージクリアです。

ステージクリアしていた場合の処理を示します。

前述のとおり通過していない点も通過していることにするため、目立つ塗り残しがあるかもしれません。そこでステージクリアと判定されたときはIsVisitsをすべてtrueにします。そのあと2秒間動作を停止させて次のステージに移行する処理をおこないます。またこのときにイベントを発生させてクライアントサイドで効果音を鳴らす処理を可能にします。

次のステージに移動する処理を示します。

更新処理

タイマーイベントが発生したときの処理を示します。

IsStopプロパティがtrueのときはキャラクタを移動させてはならないので無視します。またステージに応じて必要のないイベントも無視します。

それから永久パターン対策として敵を倒し続けた場合は動作速度を速めます。そのために処理すべきタイマーを変更しています。

必要なイベントが発生した場合はプレイヤーと敵の移動処理をおこない、当たり判定をおこないます。そのあとChangeStatusイベントを発生させてクライアントサイドで描画処理を行なうための情報を取得させます。

プレイヤーがローラーを使用しているときはプレイヤーの動作速度を速めます。別のタイマーでもMovePlayerメソッドを呼び出すことで、これを実現します。

キー操作への対応

以下はキー操作がおこなわれたときの処理です。ここではIsXKeyDownプロパティを設定しているだけです。