どうも、室井(@muroiwataru)です。
今回は以前作成したスネークゲームに機能を追加していきます。
前回の記事を読んでいない方は、先にそちらを読んでください。
目次
難易度選択機能の追加
ゲームの難易度は自機の移動速度を変更すれば調節できます。
sleep関数による待機時間を短くすれば難易度が上昇しますね。
やるべきことをリストアップすると以下のようになります。
- 難易度を切り替えるボタンの追加
- 難易度を確認できる表示の追加
- 難易度ごとにSleep関数の時間を変更
UIはこのようになります。
順番に実装していきましょう。
難易度を切り替えるボタンの追加
難易度を選択するためのコマンドボタンを作成します。
EASY・NORMAL・HARDの3つのコマンドボタンを追加しました。
コマンドボタンの作成方法は方向キーを作成したときと同様です。
忘れてしまった方は前回の記事の外部設計を確認してください。
作成したコマンドボタンに以下のプログラムを追加します。
levelの値は難易度ごとに変更します。
今回はEASYを0、NORMALを1、HARDを2としてください。
Private Sub CommandButton2_Click() If play = 0 Then level = 0 End If End Sub
levelという変数はまだ宣言していないので、標準モジュールにPublicで宣言しておきましょう。
型はInteger型を推奨します。
lebel変数は何に使うの?
Sleep関数を実行する前にlebel変数の値で分岐させることで、難易度を変更するために使います。
また、後に実装するランキング機能でも利用します。
If play = 0 Thenの意味は?
ゲームプレイ中には難易度の変更ができないようにするための処理です。
プレイ中に難易度を変更されると、ランキングが正常に機能しないためです。
難易度を確認できる表示の追加
VBAでは Cells(行, 列) = “文字列” でセルに任意の文字列を入力できます。
難易度を表示させるウィンドウを、セルを結合して表現しましょう。
今回はAA2~AE3を結合して中央揃えにしているので、Cells(2, 27) に文字列を入力します。
先程書いたコマンドボタンのプログラムに1行追加します。
Private Sub CommandButton2_Click() If play = 0 Then level = 0 Cells(2, 27) = "EASY" End If End Sub
難易度ごとにSleep関数の時間を変更
Select Case文を使って、難易度ごとに自機の移動速度を変更しましょう。
前回、Sleep 90‘待ち時間の調節 と記述した部分を以下のように書き換えます。
Select Case level Case 0 Sleep 120 Case 1 Sleep 90 Case 2 Sleep 60 End Select
キーボードからの操作
コマンドボタンのプロパティからAcceleratorを設定すると、キーボードを押下した際にクリックしたときと同様の処理が走ります。
ただし、Altキーと同時押しする必要があります。
上下左右にwasdなどを割り当てておくといいでしょう。
ランキング機能の実装
CSVファイルの作成
複数人でデータを共有できるように、csvファイルとしてユーザー名と得点を保持します。
1~3行目をEASY、4~6行目をNORMAL7~9行目をHARDの記録として使います。
1行ごとに 得点,”ユーザー名” となっているので、最初は0と適当な文字列を入れておきましょう。
Public Sub ランキング初期化() 'ランキングを保存しているCSVファイルを初期化 '製作者用、シートからは呼び出せないようにする Dim score As Integer, user As String, i As Integer score = 0: user = "Null" Open ThisWorkbook.Path & "\score.csv" For Output As #1 For i = 0 To 8 Write #1, score, user Next i Close #1 End Sub
上記のプロシージャを実行すれば、自動でscore.csvファイルが作成されます。
デバッグ中にファイルを初期化したい状況が出てくるので、書いておくといいでしょう。
外部設計
ユーザー名の入力フォームの作成
テキストボックスでユーザー名の入力フォームを作成します。
プロパティから入力できる文字数を制限できます。
ランキングの表示が崩れないように、MaxLengthを設定しておきましょう。
ランキングを表示するラベルの作成
ランキングを表示するためのラベルを作成します。
プロパティからフォントを等幅フォントに変更しておいてください。
プロポーショナルフォントだと、下の画像のように表示が崩れてしまいます。
コマンドボタンを1つ作成しておいてください。
ランキングを読み込む処理
Public Sub ランキング読み込み() Dim score(8) As Integer, user(8) As String '既存のランキングデータを読み込み Open ThisWorkbook.Path & "\score.csv" For Input As #1 For i = 0 To 8 Input #1, score(i), user(i) Next i Close #1 'ランキングを表示 For i = 0 To 6 Step 3 Select Case i Case 0 Sheet1.Label1.Caption = "EASY" & vbCrLf Case 3 Sheet1.Label1.Caption = Sheet1.Label1.Caption & "NORMAL" & vbCrLf Case 6 Sheet1.Label1.Caption = Sheet1.Label1.Caption & "HARD" & vbCrLf End Select For j = 0 To 2 Sheet1.Label1.Caption = Sheet1.Label1.Caption & j + 1 & "位" & " " & Format(user(i + j), "!@@@@@@@@") & Format(score(i + j), "@@") & vbCrLf Next j Next i End Sub
csvファイルを読み込んで、ラベルに出力する処理です。
リアルタイムで更新することは難しいので、コマンドボタンを押したときに呼び出します。
先程作成したコマンドボタンにCall文を追加しましょう。
Private Sub CommandButton5_Click() Call ランキング読み込み End Sub
ランキングを書き出す処理
Public Sub ランキング書き込み() 'ランキングに関する処理 '排他制御していないため、同時に複数人プレイすると正常に書き込まれない可能性がある Dim score(8) As Integer, user(8) As String '既存のランキングデータを読み込み Open ThisWorkbook.Path & "\score.csv" For Input As #1 For i = 0 To 8 Input #1, score(i), user(i) Next i Close #1 '難易度を判定 Select Case level Case 0 i = 0 Case 1 i = 3 Case 2 i = 6 End Select '難易度ごとに1位から3位までを保存 '配列の0~2を"EASY",3~5を"NORMAL",6~8を"HARD"の保存領域にする If cnt > score(i) Then score(i + 2) = score(i + 1): user(i + 2) = user(i + 1) score(i + 1) = score(i + 0): user(i + 1) = user(i + 0) score(i + 0) = cnt: user(i + 0) = player ElseIf cnt > score(i + 1) Then score(i + 2) = score(i + 1): user(i + 2) = user(i + 1) score(i + 1) = cnt: user(i + 1) = player ElseIf cnt > score(i + 2) Then score(i + 2) = cnt: user(i + 2) = player End If Open ThisWorkbook.Path & "\score.csv" For Output As #1 For i = 0 To 8 Write #1, score(i), user(i) Next i Close #1 End Sub
記録を更新した際に、csvファイルを更新するための処理です。
排他制御していないので、複数人が同時にゲームオーバーすると正常に更新されない可能性があります。
このプロシージャを、ゲームオーバーの判定をしているIf文の中から呼び出せるようにしましょう。
'ゲームオーバーの判定 If Y < 3 Or Y > 17 Or X < 3 Or X > 17 Or Cells(Y, X).Interior.ColorIndex = 5 Then fin = True play = False cnt = cnt - 1 Call ランキング書き込み End If
ユーザー名を記録できるように、ゲーム開始時にplayer変数にテキストボックスの値を格納できるようにします。
player変数は標準モジュールにPublicで宣言しておいてください。
型はString型です。
僕の場合はSheet1.TextBox1を使っているので、player = Sheet1.TextBox1.Text をスタートボタンに記述します。
Private Sub CommandButton1_Click() If play = False Then Call 初期化 Select Case lebel Case 0 Cells(2, 27) = "EASY" Case 1 Cells(2, 27) = "NORMAL" Case 2 Cells(2, 27) = "HARD" End Select Call ランダム配置 fin = False play = True X = 10 Y = 10 muki = 2 player = Sheet1.TextBox1.Text Call ブロック End If End Sub
最終的にスタートボタンのプログラムはこのようになりました。
Excel起動時に難易度の表示と変数の値がズレている場合があるので、難易度の表示を確認する処理も追加しています。
プレイ中の得点の表示
赤いブロックを取得するたびに、カウントアップしていくようにします。
難易度の表示と同様に、結合したセルに表示させています。
今回はU2のセルを使用しています。
赤いブロックを取得したかどうかのIf文に、下記の1行を追加します。
cntをインクリメントする前に記述してください。
Cells(2, 21) = "記録" & " " & Format(cnt, "@@")
また、初期化プロシージャに表示をリセットするための1行も追加します。
Cells(2, 21) = "記録" & " " & Format(0, "@@")
あとがき
ランキング機能はうまく実装できましたか?
csvファイルなので簡単に改ざんされますが、そこはVBAの限界ということで妥協してください。