前回から万引少年 レトロなゲームをアスキーアートでつくるを始めましたが、今回はゲーム開始後の処理を実装します。

店内を初期化

ゲームが開始されたら店内の様子がフォームに表示されます。そのためにInitStoreメソッドを呼び出します。

このメソッドは店のなかの状態を初期化します。まず制限時間をフルの状態にセットします。それから商品をすべて置かれている状態にします。そして警備員と少年の位置にゲーム開始の初期座標をセットします。

商品を初期位置にセットする

InitItemsメソッドは商品を店の棚にセットします。前回ゲームオーバーになったときのデータが残っているので、最初にLeftItemsとRightItemsをクリアします。そして商品をあるべき位置にセットします。LeftItemsは少年の左に陳列されている商品の座標のリスト、RightItemsは少年の右側に陳列されているもののリストです。

DrawStoreField1メソッドで店内を描画

前回の記事の記事の最後の部分にあるようにSキーが押されることで、シーンがScene.Store1に切り替わります。するとこれ以降はTimer.Tickイベントが発生するたびにDrawStoreField1メソッドが呼び出されます。

警備員を移動させる

DrawStoreField1メソッドでやっていることは警備員の動きをランダムに決めて左右に移動させています。ただ本当にランダムにすると右へひとつ移動したかと思えば次は左に行ったりでいつまでたっても同じ位置から変わらないという問題がおきてしまいます。そこで乱数で左右どちらに移動するか、その方向に連続でいくつ移動するかの2つの要素を決めています。

警備員の動きはbool変数のリストとしてMoveRightに格納されます。リストから取り出した値がtrueであれば右へ移動して、falseであれば左に移動します。またリストのなかが空であれば乱数でリストに格納するbool変数を生成します。

警備員を右へ移動させる処理を示します。PositionKがColumMax – 4を超えている場合は右端まで移動しているということなので右には移動できません。

これは警備員を左に移動させる処理です。

SetNewScoreStringメソッドはスコアと残り時間を上部に表示させるための文字列をフィールド変数 Scoreに格納します。レトロ感をだすために数字は全角を用いています。

少年を移動させる

キー操作がおこなわれたら少年を移動させます。

前回の記事のなかでオーバーライドされたOnKeyDownメソッドのなかではOnKeyDownBoyMoveメソッドが呼び出され、少年を移動させる処理をおこなっています。

少年もフィールドの端から外や通路以外のところに移動されては困るので移動できるかどうか確認してからPositionBoyXとPositionBoyYを変更しています。そして移動処理をおこなったらRedrawStoreFieldメソッドを呼び出してフォームを再描画しています。

CanBoyMoveメソッドは引数として渡された場所に移動できるかどうかを調べるものです。移動できない場合はそこには棚があり、商品があるかもしれません。SteelRightItemIfCanメソッドは少年の右側に商品があるか、SteelLeftItemIfCanメソッドは左側にある商品を盗むことができるかを調べて、盗むことができるなら盗む処理をおこないます。

CanBoyMoveメソッドを示します。移動先が通路であれば移動可能なのでtrueを返します。移動不可であればfalseを返します。

盗む動作の実装

SteelLeftItemIfCanメソッドにおける処理を示します。少年が移動しようとした場所に商品があればそれを盗むことができます。ただし棚には商品はそれぞれ1つずつしかおかれていません。同じ商品を何度も盗むことはできないのでLeftItemsに格納されている座標のなかから少年が移動しようとした座標と一致するものがあるのかを調べています。

そして盗むときの手の動きをそれっぽくするために成功したら手を商品棚の方向に移動させます。そのためのフラグがStealLeftSucceededです。一定時間(0.05秒)がきたらもとの状態に戻します。手を棚に伸ばすときも手をもとの状態に戻すときもすぐにRedrawStoreFieldメソッド(後述)を呼び出して再描画処理をおこないます。

商品を盗むことに成功したときにおこなわれる処理を示します。ここでは再描画の処理、効果音を鳴らす、スコアを増やす、ゲームクリア判定をおこなっています。

効果音を鳴らす処理を示します。WMPLib.WindowsMediaPlayerが使えるようにするには[参照の追加]でC:\windows\system32\wmp.dllを追加しておく必要があります。

右側の商品を盗む処理も同様に実装します。

描画に必要な文字列を取得する

RedrawStoreFieldメソッドはシーンがScene.Store1のときフォームに文字列を描画する処理をおこなうためのものです。GetStringDrawBoyメソッド、GetStringItemsメソッド、GetStringDrawKメソッドはこの次に解説します。

またStoreFieldは全角文字だけでできているのですが、足の部分は半角文字を使うので、文字列が取得されたあと「足」を半角文字2つに置換しています。

警備員や商品、少年を描画するためにはStoreFieldの文字列を一部置き換える必要があります。最初にGetStringDrawKメソッドを実行します。

警備員はこんなアスキーアートになっています。

そこでStoreFieldのなかの文字列を以下のようにして置き換えます。警備員には左向きと右向きがあります。右向きの警備員の姿は「K」、左向きだと「K」を逆にしたような形をしていて、地味に笑えます。

GetStringItemsメソッドはGetStringDrawKメソッドが返した文字列を引数にして商品を表示するためのものです。商品は$で表わされ、すでになくなっている部分には表示されません。その場合は■が表示されます。

GetStringDrawBoyメソッドはGetStringItemsメソッドが返した文字列を引数に少年も表示する文字列を返す処理をおこないます。足の部分は半角文字を使うのでここでは仮の文字「足」をいれています。leftとrightがtrueの場合は商品に手を伸ばしているような文字列を返します。

ステージクリアの処理

めでたく全部の商品を盗むことができたらステージクリアです。ステージクリアになるのかどうかはStealSucceededメソッドのなかでおこなっています。LeftItemsもRightItemsも空であればステージクリアです。そのときはシーンをScene.Clearに変更します。

シーンがScene.Clearに変更されるとTimer.Tickイベントが発生するとDrawGameClearメソッドが呼び出されるようになります。DrawGameClearメソッドのなかではGetGameClearStringメソッドが呼び出されます。タイマーのIntervalが変更され、ClearFieldの文字列が描画されます。

ClearFieldの文字列は両手をあげてバンザイをしているのですが、手を挙げている状態と下ろしている状態をいっしょにしています。何回GetGameClearStringメソッドが呼び出されたかで処理を切り分け、速い速度で何度もバンザイを繰り替えているように見せかけています。

バンザイを何度か繰り返したら次のステージにすすみます。シーンをScene.Store1に切り替え、InitStoreメソッドで店内を初期化して悪友のために新たな万引きをしてもらいます。警備員に見つかって警察に連行されるまで・・・

さて不幸にして万引きがバレてしまった場合の処理ですが、これは次回に続きます。