
Excel(VBA)でクイズゲームを作ろう!(プログラムコード解説編)
こんにちは「つけらっとゲームス」プログラム担当のとちです。
今回は「Excel(VBA)でクイズゲームを作ろう!」のプログラムコードを解説したいと思います。
▼続きの記事ですのでご覧になっていない方はコチラからどうぞ!
プログラムコードのコメント欄に打ち間違いがありましたのでコメント内容を修正しております。以前の記事で一緒に作業を進めてくださった方は改めて最新のコードをコピペしてください。
お手数をおかけして申し訳ありません。
▼最新のコードはこちら
Option Explicit
Dim QuizNo As Integer '【変数定義】現在出題されているクイズIndex
Dim QuizAns As Integer '【 〃 】現在出題されているクイズの答え
Dim UserPoint As Integer '【 〃 】プレイヤーの点数
Dim DtSt As String '【 〃 】クイズデータのワークシート名
Dim QuizMax As Integer '【 〃 】クイズデータの最大数 VerUp
Dim QuizCount As Integer '【 〃 】出題されたクイズ数 VerUp
'----------------------------------------------------------------
' UserForm 初期化
'----------------------------------------------------------------
Sub UserForm_Initialize() '
'
Randomize ' 乱数初期化[VerUp]
DtSt = "QuizData" ' クイズデータが格納されているワークシート名
TitleImage.Top = 0 ' タイトル画像を左上隅に移動させる
TitleImage.Left = 0 ' 〃
TitleLbl.Top = 72 ' タイトルラベルを所定の場所に移動させる
TitleLbl.Left = 60 ' 〃
' '
'--- VerUp [ココカラ] -------- '
'--- ループで問題数をカウントする方法 '
'--- '
'Dim wTxt As String '【変数定義】問題文検出用の変数
'Do While True '■ループ
' wTxt = Worksheets(DtSt).Cells(QuizMax + 1, 1) '├ 問題文を取得
' If wTxt = "" Or wTxt = Null Then Exit Do '├ ◆問題文が空白またはNullの場合 >> ループを抜ける
' QuizMax = QuizMax + 1 '├ クイズデータの最大数をカウントアップ
'Loop '└ ループ終端
'--- '
'--- Worksheet関数 CountIf で問題数をカウントする方法 '
'--- '
QuizMax = WorksheetFunction.CountIf(Worksheets(DtSt).Range("A1:A50"), "*")
'--- VerUp [ココマデ] ------- '
'
End Sub '
'----------------------------------------------------------------
' はじめるボタンをクリック
'----------------------------------------------------------------
Sub StartBtn_Click() '
'
QuizNo = 1 '[初期化]出題されるクイズIndex
'
'--- VerUp [ココカラ] -------- '
Do While True '■ループ
Worksheets(DtSt).Cells(QuizNo, 7) = "" '├ 出題済みセルを初期化
QuizNo = QuizNo + 1 '├ 出題されるクイズIndexのカウントアップ
If QuizNo > QuizMax Then Exit Do '├ ◆クイズIndexがクイズデータの最大数を超えた場合 >> ループを抜ける
Loop '└ ループ終端
'--- VerUp [ココマデ] ------- '
'
QuizAns = 0 '[初期化]出題されたクイズの答え
UserPoint = 0 '[初期化]プレイヤーの点数
QuizCount = 1 '[初期化]出題されたクイズ数
'
UserPointLbl.Caption = UserPoint & "点" ' 答案用紙の点数表示
Nokoribl.Caption = "残り10問" ' 問題残り数の表示
'
TitleImage.Visible = False ' タイトル画像 非表示化
TitleLbl.Visible = False ' タイトルラベル非表示化
StartBtn.Visible = False ' はじめるボタン非表示化
QuizDataGet ' クイズデータを取得
'
End Sub '
'----------------------------------------------------------------
' 次へボタンをクリック
'----------------------------------------------------------------
Sub NextBtn_Click() '
'
If QuizCount >= 11 Then '■出題されたクイズ数が11以上の場合 終了処理
Dim KekaTx As String '├【変数定義】結果テキスト
TitleImage.Visible = True '├ タイトル画像 表示
TitleLbl.Visible = True '├ タイトルラベル表示
StartBtn.Visible = True '├ はじめるボタン表示
KekaTx = "難しかったかな?" '├[初期化]結果テキスト
If UserPoint >= 30 Then KekaTx = "ちょっと残念..." '├◆点数が 30点以上のテキストを結果テキストへ代入
If UserPoint >= 60 Then KekaTx = "まぁまぁかな?" '├◆点数が 60点以上 〃 〃
If UserPoint >= 80 Then KekaTx = "惜しい!" '├◆点数が 80点以上 〃 〃
If UserPoint >= 100 Then KekaTx = "満点おめでとう!" '├◆点数が100点以上 〃 〃
TitleLbl.Caption = KekaTx '├ 結果テキストの画面反映
StartBtn.Caption = "もう1回!" '├ はじめるボタンのキャプション変更
Else '■出題されるクイズIndexが11以上ではない場合
QuizDataGet '└ 次のクイズデータを取得
End If '
'
End Sub '
'----------------------------------------------------------------
' 選択肢ボタン1~4をクリック
'----------------------------------------------------------------
Sub QSelBtn1_Click() '
If QuizAns = 1 Then UserPoint = UserPoint + 10 '■クイズの答えが「1」の場合 >> 点数+10
QAnsMB1.Visible = True 'マルバツラベル1を表示
QuizAnsSelectAfter '解答後の処理
End Sub '
Sub QSelBtn2_Click() '
If QuizAns = 2 Then UserPoint = UserPoint + 10 '■クイズの答えが「2」の場合 >> 点数+10
QAnsMB2.Visible = True 'マルバツラベル2を表示
QuizAnsSelectAfter '解答後の処理
End Sub '
Sub QSelBtn3_Click() '
If QuizAns = 3 Then UserPoint = UserPoint + 10 '■クイズの答えが「3」の場合 >> 点数+10
QAnsMB3.Visible = True 'マルバツラベル3を表示
QuizAnsSelectAfter '解答後の処理
End Sub '
Sub QSelBtn4_Click() '
If QuizAns = 4 Then UserPoint = UserPoint + 10 '■クイズの答えが「4」の場合 >> 点数+10
QAnsMB4.Visible = True 'マルバツラベル4を表示
QuizAnsSelectAfter '解答後の処理
End Sub '
'----------------------------------------------------------------
' 解答後の処理
'----------------------------------------------------------------
Sub QuizAnsSelectAfter() '
'
QSelBtn1.Enabled = False ' 選択肢ボタン1 クリック不可
QSelBtn2.Enabled = False ' 〃 2 〃
QSelBtn3.Enabled = False ' 〃 3 〃
QSelBtn4.Enabled = False ' 〃 4 〃
'
QAnsLbl.Visible = True '答えラベル 表示
NextBtn.Visible = True '次へボタン 表示
QuizCount = QuizCount + 1 '出題されたクイズ数のカウントアップ
UserPointLbl.Caption = UserPoint & "点" '点数の更新
Nokoribl.Caption = "残り" & (11 - QuizCount) & "問" '残り問題数の更新
NextBtn.SetFocus '次へボタンにフォーカスを移す
'
NextBtn.Caption = "次へ" '次へボタンのキャプションを初期化 [バグ対応][VerUp]
If QuizCount >= 11 Then NextBtn.Caption = "結果発表" '■クイズIndexが11以上の場合 >> 次へボタンのキャプションを結果発表にする[VerUp]
'
End Sub '
'----------------------------------------------------------------
' 問題文と正解を取得し、画面表示する
'----------------------------------------------------------------
Sub QuizDataGet() '
'
Dim ZumiFlg As String '【変数定義】出題済みフラグ VerUp
NextBtn.Visible = False ' 次へボタン 非表示化
QAnsLbl.Visible = False ' 答えラベル 〃
QAnsMB1.Visible = False ' マルバツラベル1 〃
QAnsMB2.Visible = False ' マルバツラベル2 〃
QAnsMB3.Visible = False ' マルバツラベル3 〃
QAnsMB4.Visible = False ' マルバツラベル4 〃
QSelBtn1.Enabled = True ' 選択肢ボタン1 クリック可
QSelBtn2.Enabled = True ' 選択肢ボタン2 〃
QSelBtn3.Enabled = True ' 選択肢ボタン3 〃
QSelBtn4.Enabled = True ' 選択肢ボタン4 〃
'
'--- VerUp [ココカラ] -------- '
QuizNo = fRandom(QuizMax, 1) ' 出題されるクイズIndexをランダム取得
Do While True ' ■ループ
ZumiFlg = Worksheets(DtSt).Cells(QuizNo, 7) ' ├ 出題済みフラグを取得
If ZumiFlg = "" Then Exit Do ' ├ ◆出題済みフラグが立っていない場合 >> ループを抜ける
QuizNo = QuizNo + 1 ' ├ 出題されるクイズIndexを+1
If QuizNo > QuizCount Then QuizNo = 1 ' ├ ◆クイズIndexがクイズデータの最大数を超えた場合 >> クイズIndexを1に戻す
Loop ' └ ループ終端
'--- VerUp [ココマデ] ------- '
'
QuizTxLbl.Caption = Worksheets(DtSt).Cells(QuizNo, 1) ' 問題 データ取得
QSelBtn1.Caption = Worksheets(DtSt).Cells(QuizNo, 2) ' 選択肢1 〃
QSelBtn2.Caption = Worksheets(DtSt).Cells(QuizNo, 3) ' 選択肢2 〃
QSelBtn3.Caption = Worksheets(DtSt).Cells(QuizNo, 4) ' 選択肢3 〃
QSelBtn4.Caption = Worksheets(DtSt).Cells(QuizNo, 5) ' 選択肢4 〃
QuizAns = Val(Worksheets(DtSt).Cells(QuizNo, 6)) ' 答え 〃
Worksheets(DtSt).Cells(QuizNo, 7) = "zumi" ' 出題済みフラグを立てる VerUp
'
'--- VerUp [ココカラ] -------- '
QSelBtn3.Visible = True ' 選択肢ボタン3 表示化(初期化)
QSelBtn4.Visible = True ' 選択肢ボタン4 表示化(初期化)
If QSelBtn3.Caption = "" Then QSelBtn3.Visible = False ' ■選択肢ボタン3のキャプションが空白の場合 >> 選択肢ボタン3を非表示化
If QSelBtn4.Caption = "" Then QSelBtn4.Visible = False ' ■選択肢ボタン4のキャプションが空白の場合 >> 選択肢ボタン4を非表示化
'--- VerUp [ココマデ] ------- '
'
'答えラベルに表示するテキストを編集 '
QAnsLbl.Caption = "答:" & Worksheets(DtSt).Cells(QuizNo, QuizAns + 1)
QAnsMB1.Caption = "×" ' マルバツラベルの初期化
QAnsMB2.Caption = "×" ' 〃
QAnsMB3.Caption = "×" ' 〃
QAnsMB4.Caption = "×" ' 〃
If QuizAns = 1 Then QAnsMB1.Caption = "〇" '■答えが「1」の場合 >> マルバツラベル1を〇にする
If QuizAns = 2 Then QAnsMB2.Caption = "〇" '■答えが「2」の場合 >> マルバツラベル2を〇にする
If QuizAns = 3 Then QAnsMB3.Caption = "〇" '■答えが「3」の場合 >> マルバツラベル3を〇にする
If QuizAns = 4 Then QAnsMB4.Caption = "〇" '■答えが「4」の場合 >> マルバツラベル4を〇にする
End Sub '
'----------------------------------------------------------------
' 最大値と最小値を指定した乱数取得ファンクション VerUp
'----------------------------------------------------------------
Function fRandom(dMax As Integer, dMin As Integer) '
fRandom = Int(dMax * Rnd + dMin) ' 最小~最大値の間の値を乱数を用いて返答する
End Function '
今回は応用編で改良した後のコードを、プロシージャや処理ごとに分けて解説していきます。コードの文中にもコメントで説明が書かれていますので、そちらも参考にしてみてくださいね。
非常に長い記事になっています。
学習方法としては自分なりにコード全体を見て、わからない部分(何をしているのかいまいちわからん部分)の解説を読むと良いでしょう。
全体の変数定義
まずはオレンジの枠で囲まれた部分から説明します。

Option Explicit
Dim QuizNo As Integer '【変数定義】現在出題されているクイズIndex
Dim QuizAns As Integer '【 〃 】現在出題されているクイズの答え
Dim UserPoint As Integer '【 〃 】プレイヤーの点数
Dim DtSt As String '【 〃 】クイズデータのワークシート名
Dim QuizMax As Integer '【 〃 】クイズデータの最大数 VerUp
Dim QuizCount As Integer '【 〃 】出題されたクイズ数 VerUp
最初の1行目にある「Option Explicit」ですが、これは以前の「Excel(VBA)で簡単なゲームを作る(プログラムコード解説編)」でも触れています。
お手数をおかけしますがそちらをご覧ください。
2行目以降はゲーム内の制御に使用する変数定義をしています。
コード内のコメントからもわかるように、出題されているクイズIndex、答え、点数といった項目を管理しています。
・Dim QuizNo As Integer
画面に表示されているクイズのIndexが入る変数です。ランダムに得られた数字が入ります。これによってゲームをする度に出題される順番や内容が異なります。
・Dim QuizAns As Integer
画面に表示されているクイズの答えが入る変数です。この値とプレイヤーの解答したボタン番号を比較して同じであれば正解としています。
・Dim UserPoint As Integer
プレイヤーの点数を管理しています。正解すると+10点です。
・Dim DtSt As String
問題を置いているワークシート名を入れておく変数です。
コード中にその都度ワークシート名を入れても良いのですが、ゲーム中に変化する部分ではないので定数として使用します。
・Dim QuizMax As Integer
応用編で追加した変数です。ワークシートに存在するクイズ数を入れておきます。このゲームはランダムに出題される仕組みなので乱数の上限として使用します。
・Dim QuizCount As Integer
応用編で追加した変数です。出題された問題の数をカウントアップします。初回記事のシステムではQuizNoが10になると10問出題したと判断していましたが、ランダムに出題されるように改良したため、現時点で何問目かを判断する為に追加されました。
UserForm 初期化
引き続き、次のオレンジ枠の中身を説明します。
この部分はユーザーフォームの初期化タイミングで処理されます。ゲームが起動するタイミングでもありますのでゲーム全体で使用する変数などを準備、整理しておきます。

'----------------------------------------------------------------
' UserForm 初期化
'----------------------------------------------------------------
Sub UserForm_Initialize() '
'
Randomize ' 乱数初期化[VerUp]
DtSt = "QuizData" ' クイズデータが格納されているワークシート名
TitleImage.Top = 0 ' タイトル画像を左上隅に移動させる
TitleImage.Left = 0 ' 〃
TitleLbl.Top = 72 ' タイトルラベルを所定の場所に移動させる
TitleLbl.Left = 60 ' 〃
' '
'--- VerUp [ココカラ] -------- '
'--- ループで問題数をカウントする方法 '
'--- '
'Dim wTxt As String '【変数定義】問題文検出用の変数
'Do While True '■ループ
' wTxt = Worksheets(DtSt).Cells(QuizMax + 1, 1) '├ 問題文を取得
' If wTxt = "" Or wTxt = Null Then Exit Do '├ ◆問題文が空白またはNullの場合 >> ループを抜ける
' QuizMax = QuizMax + 1 '├ クイズデータの最大数をカウントアップ
'Loop '└ ループ終端
'--- '
'--- Worksheet関数 CountIf で問題数をカウントする方法 '
'--- '
QuizMax = WorksheetFunction.CountIf(Worksheets(DtSt).Range("A1:A50"), "*")
'--- VerUp [ココマデ] ------- '
'
End Sub '
・Randomize
改良版で追加された行です。Randomizeと打つことでRnd関数の乱数ジェネレーターを初期化してます。Randomizeの後に数字(引数)を付けると、その数字がシード値となります。省略するとシステムタイマーからシード値を得ます。
…難しいことを書いているような気がしますので、もうちょっと説明。
シード値が同じ場合、その後のRnd関数は同値を返答するので再現性が生まれます。マインクラフトで世界を作る際にシード値が同じであれば、同じ世界が生まれるのと同じです。
ここでは出題の順番を完全にランダムにしたいので引数を省略してシステムタイマーからシード値を得ています。
・DtSt = "QuizData"
問題データを入力しておいたワークシートの名前を代入しています。
・TitleImage.Top = 0
この行と次行はタイトル画像の位置を左上隅に固定化しています。
・TitleLbl.Top = 72
この行と次行はタイトルラベルを所定位置に固定化しています。
・ループで問題数をカウントする方法
・Worksheet関数 CountIf で問題数をカウントする方法
このコメントの付近ではQuizMax(ワークシートに存在するクイズ数)を数えています。複数のやり方があるのでパッと思いついた方法を2つコード内に残しました。
「ループで問題数をカウントする方法」ではDoWhile文を用いてワークシート内の問題文があるセルを縦に探索し空文字("")またはnullが見つかるまでループしています。1件毎に調査している形ですね。
「Worksheet関数 CountIf で問題数をカウントする方法」ではWorksheet関数を用いて1行で解決しています。
どちらも同じQuizMax(クイズ数)を取得できますが、Worksheet関数はその名の通りワークシートがあるから使用できる関数です。アルゴリズム的にはループで問題数をカウントする方法を覚えておいて損はないでしょう。
はじめるボタンをクリック
この部分ではゲーム1プレイに必要な変数を初期化し、新たに始めるゲームの準備を行っています。

'----------------------------------------------------------------
' はじめるボタンをクリック
'----------------------------------------------------------------
Sub StartBtn_Click() '
'
QuizNo = 1 '[初期化]出題されるクイズIndex
'
'--- VerUp [ココカラ] -------- '
Do While True '■ループ
Worksheets(DtSt).Cells(QuizNo, 7) = "" '├ 出題済みセルを初期化
QuizNo = QuizNo + 1 '├ 出題されるクイズIndexのカウントアップ
If QuizNo > QuizMax Then Exit Do '├ ◆クイズIndexがクイズデータの最大数を超えた場合 >> ループを抜ける
Loop '└ ループ終端
'--- VerUp [ココマデ] ------- '
'
QuizAns = 0 '[初期化]出題されたクイズの答え
UserPoint = 0 '[初期化]プレイヤーの点数
QuizCount = 1 '[初期化]出題されたクイズ数
'
UserPointLbl.Caption = UserPoint & "点" ' 答案用紙の点数表示
Nokoribl.Caption = "残り10問" ' 問題残り数の表示
'
TitleImage.Visible = False ' タイトル画像 非表示化
TitleLbl.Visible = False ' タイトルラベル非表示化
StartBtn.Visible = False ' はじめるボタン非表示化
QuizDataGet ' クイズデータを取得
'
End Sub '
・QuizNo = 1
はじめるボタンを押してまずやっていることが出題されるクイズのIndexを1に初期化しているコードです。この後で処理をするDoWhile文の中で使用するカウンタとして使用しているので初期化しています。
・Do While True
改良版で追加されたDoWhile文です。
このループは常にTrueなので通常終了することはありません。
文中のIf文にExitDoがあるので、その条件によってループを終えています。
条件は何かというとカウンタであるQuizNoがQuizMaxを超えたか…です。QuizMaxは問題数なので全件ループをしているんですね。
全件ループ中に何をしているのかを見ると、問題があるワークシートの7列目(G列)を空文字にしています。実は出題された問題のG列には"zumi"とフラグを立てているんです。

これによって、1プレイ中に同じ問題が出ないように制御しています。
ゲームをはじめる時にこの「フラグを全件消去している処理」ということになりますね。
・QuizAns = 0
・UserPoint = 0
・QuizCount = 1
この3行はゲーム1プレイ中に使う変数を初期化しています。
・UserPointLbl.Caption = UserPoint & "点"
・Nokoribl.Caption = "残り10問"
この2行で画面表示されているプレイヤーの点数、問題の残数を初期化しています。
・TitleImage.Visible = False
・TitleLbl.Visible = False
・StartBtn.Visible = False
この3行はゲーム中には不必要な項目であるタイトル画面で使用したオブジェクト(画像、ラベル、ボタン)を非表示化しています。
・QuizDataGet
この行はサブルーチンQuizDataGetを動かしています。
QuizDataGetについては後述しますね。
次へボタンをクリック
この部分ではプレイヤーの解答に対して正誤を表示した後の処理を記述しています。出題数が11問目以上(10問までなのでありえない)になった場合は結果を表示し、それ以外であれば次の問題を取得します。

'----------------------------------------------------------------
' 次へボタンをクリック
'----------------------------------------------------------------
Sub NextBtn_Click() '
'
If QuizCount >= 11 Then '■出題されたクイズ数が11以上の場合 終了処理
Dim KekaTx As String '├【変数定義】結果テキスト
TitleImage.Visible = True '├ タイトル画像 表示
TitleLbl.Visible = True '├ タイトルラベル表示
StartBtn.Visible = True '├ はじめるボタン表示
KekaTx = "難しかったかな?" '├[初期化]結果テキスト
If UserPoint >= 30 Then KekaTx = "ちょっと残念..." '├◆点数が 30点以上のテキストを結果テキストへ代入
If UserPoint >= 60 Then KekaTx = "まぁまぁかな?" '├◆点数が 60点以上 〃 〃
If UserPoint >= 80 Then KekaTx = "惜しい!" '├◆点数が 80点以上 〃 〃
If UserPoint >= 100 Then KekaTx = "満点おめでとう!" '├◆点数が100点以上 〃 〃
TitleLbl.Caption = KekaTx '├ 結果テキストの画面反映
StartBtn.Caption = "もう1回!" '├ はじめるボタンのキャプション変更
Else '■出題されるクイズIndexが11以上ではない場合
QuizDataGet '└ 次のクイズデータを取得
End If '
'
End Sub '
・If QuizCount >= 11 Then
出題された問題が11問以上になっているかを判断しているIf文です。
10問で1ゲームなので、11問以上になったらありえない状況…つまりゲーム終了タイミングであると判断できます。
・Dim KekaTx As String
結果の文字列を編集する為の文字列変数です。
この処理の中でしか使用しないので、If文の中で変数定義しています。
・TitleImage.Visible = True
・TitleLbl.Visible = True
・StartBtn.Visible = True
この3行は非表示化していたタイトル画面のオブジェクトを表示するように変更しています。タイトル画面で使用したオブジェクトを再利用しゲーム結果を表示するための処理です。
・KekaTx = "難しかったかな?"
・If UserPoint >= 30 Then KekaTx = "ちょっと残念..."
・If UserPoint >= 60 Then KekaTx = "まぁまぁかな?"
・If UserPoint >= 80 Then KekaTx = "惜しい!"
・If UserPoint >= 100 Then KekaTx = "満点おめでとう!"
・TitleLbl.Caption = KekaTx
ここでは点数を判断基準にゲーム結果を切り替えています。
まず1行目で評価の文言を初期化、2行目は30点以上の場合、3行目は60点以上、4行目は80点以上、5行目は満点であるか判断しています。
点数によって表示する文言が変わるようになっているのがわかりますね。
最後の6行目ではタイトルラベルに取得した文言を反映させています。
(※タイトルラベルはタイトル画面のオブジェクトの再利用です!)
・StartBtn.Caption = "もう1回!"
タイトル画面では「はじめる」と表示されていたスタートボタンのキャプションを「もう1回!」に変更しています。「ゲーム再開」と「ゲーム開始」の初期化は同じような処理を要します。こういった再利用をすることでコードが短くなったりします。
・QuizDataGet
出題された問題が11問以上ではない(Else)場合の処理です。
10問までは次の問題が必要です。なので「はじめる」ボタンを押したときと同様にサブルーチンQuizDataGetを動かします。
選択肢ボタン1~4をクリック
ここでは出題に対してプレイヤーが選択肢ボタンを押した際の処理を書いています。内容的には同じなので選択肢ボタン1について説明します。

'----------------------------------------------------------------
' 選択肢ボタン1~4をクリック
'----------------------------------------------------------------
Sub QSelBtn1_Click() '
If QuizAns = 1 Then UserPoint = UserPoint + 10 '■クイズの答えが「1」の場合 >> 点数+10
QAnsMB1.Visible = True 'マルバツラベル1を表示
QuizAnsSelectAfter '解答後の処理
End Sub '
・If QuizAns = 1 Then UserPoint = UserPoint + 10
・QAnsMB1.Visible = True
クイズの答えはQuizAnsに入っています。押されたボタンとQuizAnsが同じ場合はUserPoint(得点)に10点加算しています。
同時に、プレイヤーの選択が正解か間違いかを表示するラベルQAnsMB1を非表示から表示に切り替えています。
他のボタンでは…例えば選択肢ボタン2の場合は、以下のようになります。
If QuizAns = 2 Then UserPoint = UserPoint + 10
QAnsMB2.Visible = True
・QuizAnsSelectAfter
プレイヤーの選択後の処理をするサブルーチンQuizAnsSelectAfterを動かしています。これはどのボタンを押しても必要な処理なので、各ボタン全て共通です。
解答後の処理
この部分では、プレイヤーが選択肢を選んだ後の処理をしています。
正解であっても不正解であっても共通する処理をしています。

'----------------------------------------------------------------
' 解答後の処理
'----------------------------------------------------------------
Sub QuizAnsSelectAfter() '
'
QSelBtn1.Enabled = False ' 選択肢ボタン1 クリック不可
QSelBtn2.Enabled = False ' 〃 2 〃
QSelBtn3.Enabled = False ' 〃 3 〃
QSelBtn4.Enabled = False ' 〃 4 〃
'
QAnsLbl.Visible = True '答えラベル 表示
NextBtn.Visible = True '次へボタン 表示
QuizCount = QuizCount + 1 '出題されたクイズ数のカウントアップ
UserPointLbl.Caption = UserPoint & "点" '点数の更新
Nokoribl.Caption = "残り" & (11 - QuizCount) & "問" '残り問題数の更新
NextBtn.SetFocus '次へボタンにフォーカスを移す
'
NextBtn.Caption = "次へ" '次へボタンのキャプションを初期化 [バグ対応][VerUp]
If QuizCount >= 11 Then NextBtn.Caption = "結果発表" '■クイズIndexが11以上の場合 >> 次へボタンのキャプションを結果発表にする[VerUp]
'
End Sub '
・QSelBtn1.Enabled = False
ここを含む4行は出題された問題に対して解答後なので二重解答を防ぐ必要があります。なので、それぞれ選択肢ボタンを押せない状態にしています。
・QAnsLbl.Visible = True
・NextBtn.Visible = True
答えラベルと次へボタンを非表示から表示状態に切り替えています。
・QuizCount = QuizCount + 1
・UserPointLbl.Caption = UserPoint & "点"
・Nokoribl.Caption = "残り" & (11 - QuizCount) & "問"
この3行では1問解答後なのでQuizCountを+1、点数が変化している可能性があるので画面表示を更新、残り問題数の表示も更新しています。
・NextBtn.SetFocus
次へボタンにカーソルを移しています。
・NextBtn.Caption = "次へ"
・If QuizCount >= 11 Then NextBtn.Caption = "結果発表"
1行目で次へボタンのキャプションを初期化し「次へ」にしています。
その理由が2行目にあります。
2行目では出題数が11以上の場合(ありえない場合)はゲーム終了なので次へボタンのキャプションを「結果発表」に変更しています。
問題文と正解を取得し、画面表示する
この部分はちょっと長いのですが中身を見るとそこまで複雑ではないハズです。新しい問題と正解を取得するのと同時に1問毎に必要な画面の初期化を行っています。

'----------------------------------------------------------------
' 問題文と正解を取得し、画面表示する
'----------------------------------------------------------------
Sub QuizDataGet() '
'
Dim ZumiFlg As String '【変数定義】出題済みフラグ VerUp
NextBtn.Visible = False ' 次へボタン 非表示化
QAnsLbl.Visible = False ' 答えラベル 〃
QAnsMB1.Visible = False ' マルバツラベル1 〃
QAnsMB2.Visible = False ' マルバツラベル2 〃
QAnsMB3.Visible = False ' マルバツラベル3 〃
QAnsMB4.Visible = False ' マルバツラベル4 〃
QSelBtn1.Enabled = True ' 選択肢ボタン1 クリック可
QSelBtn2.Enabled = True ' 選択肢ボタン2 〃
QSelBtn3.Enabled = True ' 選択肢ボタン3 〃
QSelBtn4.Enabled = True ' 選択肢ボタン4 〃
'
'--- VerUp [ココカラ] -------- '
QuizNo = fRandom(QuizMax, 1) ' 出題されるクイズIndexをランダム取得
Do While True ' ■ループ
ZumiFlg = Worksheets(DtSt).Cells(QuizNo, 7) ' ├ 出題済みフラグを取得
If ZumiFlg = "" Then Exit Do ' ├ ◆出題済みフラグが立っていない場合 >> ループを抜ける
QuizNo = QuizNo + 1 ' ├ 出題されるクイズIndexを+1
If QuizNo > QuizCount Then QuizNo = 1 ' ├ ◆クイズIndexがクイズデータの最大数を超えた場合 >> クイズIndexを1に戻す
Loop ' └ ループ終端
'--- VerUp [ココマデ] ------- '
'
QuizTxLbl.Caption = Worksheets(DtSt).Cells(QuizNo, 1) ' 問題 データ取得
QSelBtn1.Caption = Worksheets(DtSt).Cells(QuizNo, 2) ' 選択肢1 〃
QSelBtn2.Caption = Worksheets(DtSt).Cells(QuizNo, 3) ' 選択肢2 〃
QSelBtn3.Caption = Worksheets(DtSt).Cells(QuizNo, 4) ' 選択肢3 〃
QSelBtn4.Caption = Worksheets(DtSt).Cells(QuizNo, 5) ' 選択肢4 〃
QuizAns = Val(Worksheets(DtSt).Cells(QuizNo, 6)) ' 答え 〃
Worksheets(DtSt).Cells(QuizNo, 7) = "zumi" ' 出題済みフラグを立てる VerUp
'
'--- VerUp [ココカラ] -------- '
QSelBtn3.Visible = True ' 選択肢ボタン3 表示化(初期化)
QSelBtn4.Visible = True ' 選択肢ボタン4 表示化(初期化)
If QSelBtn3.Caption = "" Then QSelBtn3.Visible = False ' ■選択肢ボタン3のキャプションが空白の場合 >> 選択肢ボタン3を非表示化
If QSelBtn4.Caption = "" Then QSelBtn4.Visible = False ' ■選択肢ボタン4のキャプションが空白の場合 >> 選択肢ボタン4を非表示化
'--- VerUp [ココマデ] ------- '
'
'答えラベルに表示するテキストを編集 '
QAnsLbl.Caption = "答:" & Worksheets(DtSt).Cells(QuizNo, QuizAns + 1)
QAnsMB1.Caption = "×" ' マルバツラベルの初期化
QAnsMB2.Caption = "×" ' 〃
QAnsMB3.Caption = "×" ' 〃
QAnsMB4.Caption = "×" ' 〃
If QuizAns = 1 Then QAnsMB1.Caption = "〇" '■答えが「1」の場合 >> マルバツラベル1を〇にする
If QuizAns = 2 Then QAnsMB2.Caption = "〇" '■答えが「2」の場合 >> マルバツラベル2を〇にする
If QuizAns = 3 Then QAnsMB3.Caption = "〇" '■答えが「3」の場合 >> マルバツラベル3を〇にする
If QuizAns = 4 Then QAnsMB4.Caption = "〇" '■答えが「4」の場合 >> マルバツラベル4を〇にする
End Sub '
・Dim ZumiFlg As String
ワークシートのG列に何か入っていた場合は出題済みなので、出題候補から外すためのフラグを変数として保持するための変数定義です。
・NextBtn.Visible = False
・QAnsLbl.Visible = False
「次へ」ボタンと正解を表示しているラベルを非表示化しています。
次の問題が出題されたら、まずは選択肢を選んで欲しいですし、過去の正解は不要ですからね…
・QAnsMB1.Visible = False
この行を含む4行はプレイヤーが選択した解答の正誤を表示するラベルを非表示化しています。次の問題に対する準備ですね。
・QSelBtn1.Enabled = True
この行を含む4行は選択肢ボタンを全て操作可能に変更しています。
つまり、解答後に押せなくした選択肢ボタンを押せるように戻しています。
・QuizNo = fRandom(QuizMax, 1)
応用編で追加した部分です。次に出題されるクイズのIndexをランダムに取得するためにfRandomファンクションを呼び出しています。fRandomに関しては後述します。
・Do While True
ここも応用編で追加した部分です。この前の行で取得した乱数のG列にzumiが入っていた場合、この問題は出題済みです。この場合はその次の問題を出題します。その次もzumiの場合は更にその次を出題します。
もし出題する予定のQuizNoがQuizMax(問題数)を超えてしまったらQuizNoを1にします。
Zumiが入っていない(これまで出題されていない)問題を見つけるまでループし続ける仕組みなのがわかりますね。
・QuizTxLbl.Caption = Worksheets(DtSt).Cells(QuizNo, 1)
・QSelBtn1.Caption = Worksheets(DtSt).Cells(QuizNo, 2)
・QSelBtn2.Caption = Worksheets(DtSt).Cells(QuizNo, 3)
・QSelBtn3.Caption = Worksheets(DtSt).Cells(QuizNo, 4)
・QSelBtn4.Caption = Worksheets(DtSt).Cells(QuizNo, 5)
・QuizAns = Val(Worksheets(DtSt).Cells(QuizNo, 6))
・Worksheets(DtSt).Cells(QuizNo, 7) = "zumi"
この部分では1行目でクイズ問題文、2行目で選択肢1、3行目が選択肢2、4行目が選択肢3、5行目が選択肢4、6行目が答え番号を取得しています。
取得した内容はラベルやボタンに反映させています。
7行目では、その問題のG列に「zumi」を入れています。
これによって「この問題は出題済みですよ」と判断できるようになります。
・QSelBtn3.Visible = True
・QSelBtn4.Visible = True
・If QSelBtn3.Caption = "" Then QSelBtn3.Visible = False
・If QSelBtn4.Caption = "" Then QSelBtn4.Visible = False
この部分は応用編で追加した部分です。
最初の2行で選択肢ボタンの3~4番目を必ず表示するようにしています。
3行目で選択肢3のキャプションが空文字("")の場合は選択肢3ボタンを非表示化、4行目で選択肢4のキャプションが空文字("")の場合は選択肢4ボタンを非表示化しています。
2~4択問題が切り替わっても問題なく動作するようになっています。
・QAnsLbl.Caption = "答:" & Worksheets(DtSt).Cells(QuizNo, QuizAns + 1)
少し長い行ですね。この行では問題の解答をワークシートから取得、編集して画面に反映させています。ワークシートのQuizNo行のQuizAns+1列を答えとして使用しています。
・QAnsMB1.Caption = "×"
この行を含む4行では、プレイヤーの選択が合っているか否かを表示する〇✕ラベルを初期化しています。一旦全てを×にしています。
・If QuizAns = 1 Then QAnsMB1.Caption = "〇"
この行を含む4行で、プレイヤーの選択が合っているか否かを表示する〇✕ラベルで且つ正解の場合を〇にしています。
最大値と最小値を指定した乱数取得
ここでは1~問題数の乱数取得を行っています。

'----------------------------------------------------------------
' 最大値と最小値を指定した乱数取得ファンクション VerUp
'----------------------------------------------------------------
Function fRandom(dMax As Integer, dMin As Integer) '
fRandom = Int(dMax * Rnd + dMin) ' 最小~最大値の間の値を乱数を用いて返答する
End Function '
・Function fRandom(dMax As Integer, dMin As Integer)
fRandomの後に続く括弧は引数を表しています。
dMaxは最大、dMinは最小値です。これらの範囲内の乱数を返答します。
・fRandom = Int(dMax * Rnd + dMin)
Rnd関数は、0以上1未満の値を返答します。
これによって乱数の範囲指定が可能です。
おわりに
長い記事でしたがここまで読んだ方、本当にお疲れ様です。
コードを打っている時は、既に頭の中でイメージが浮かび上がっている状態なので長く感じないんですけど、1行毎に説明すると長くなっちゃいます。
そこまで複雑なことはしていません。同じような処理はサブルーチン(ファンクション)化するとコードの量は減るんですが、これまた慣れないと難しいんですよね…
これに関してはコードを打ち続けることで雰囲気として習得ができると思いますよ。
以降はオススメ記事の紹介です。
「読むとゲームができる」記事は、このマガジンにまとめています。
情報関連の勉強をしている方、復習したい方にはコチラ!
基本情報技術者試験のアルゴリズムとか苦手!って方にもオススメです。
いいなと思ったら応援しよう!
