文系人間がプログラミングをはじめてみた。

プログラミング初心者のゼロからの勉強記録。

マクロで作ったマインスイーパーの解説 詳細編 爆弾を設置する

どうもこんばんは。

 

今回もマクロで作ったマインスイーパーの解説をしていきます。

どんな感じのマインスイーパーになっているかはこちらからご確認ください。

programminghajimetemita.hatenablog.com

 

今回は爆弾を設置する処理について解説していきたいと思います。

 

 

1.コードの内容

まずは爆弾を設置するマクロのコードをご紹介します。


このコードの中であらかじめ定義しておいた変数・定数が出てきています。

その内容について以下に記載しておきます。

■ 変数

r:行番号を表す変数

c:列番号を表す変数

bottom_r:マス目の一番下の行の行番号(難易度に応じて変化)

rightedge_c:マス目の一番右の列の列番号(難易度に応じて変化)

icon_b:爆弾マーク(💣)を表す変数
(コード上で爆弾マークを記載すると文字化けするのでセルの値を参照するようにしています)

cnt:マス目内にある爆弾の個数をカウントするための変数

start_b:爆弾の初期個数(難易度に応じて変化)

■ 定数

top_r:マス目の一番上の行の行番号

leftedge_c:マス目の一番左の列の列番号

 

2.マインスイーパーの挙動

コードの解説に入る前にマインスイーパーの挙動について触れておきます。

 

コードを一から考えるうえでは、実現したい動きを頭に入れておくことが非常に重要と私は思いますので、

少し冗長かもしれませんが触れておきたいと思います。

 

爆弾の設置に関するマインスイーパーの挙動です。

私がコードを考えたとき、以下のような特徴があると考えました。

 

・ゲーム画面のマス目内のランダムな位置に、規定個数の爆弾が設置される

・ゲームごとに爆弾の設置位置が変わる

 

上記を踏まえると、以下のような条件が必要と考えることができます

 

・マス目内のランダムな位置を取得する

・規定個数の爆弾を設置する

・設置位置は常にランダムである

 

これを念頭においてコードの内容に入っていきましょう。

 

3.コードの内容解説

では上記コードについて一つずつ解説していきます。

ゲーム画面設定時にも出てきた、画面更新停止のコードです。

これを入れておくことでマクロの処理速度を上げることができます。

 

なお、下の行で出てくる以下のコードは上記と逆で画面更新を再開するコードになります。

これを入れることでマクロで処理した結果が画面に反映されます。

 

繰返処理を行うためのコードです。

DoとLoopに挟まれたコードが、Untilの右隣に記載されている終了条件を満たすまで、

繰り返し行われます。

 

繰返処理の内容は以下で細かく解説しますが、

やっていることは、マス目内のランダムな位置に爆弾を設置する処理です。

 

また、終了条件はマス目内に設置された爆弾の個数が爆弾の初期個数に等しくなることになります。

 

総括すると、この繰返処理では、

爆弾の初期個数分、爆弾がマス目内に設置されるまで、

マス目内のランダムな位置に爆弾を設置する処理を繰り返す

という処理をやっていることになります。

 

これは乱数を初期化するために入れているコードになります。

上記コード以下の行で、マス目内のランダムな位置を設定するため、

Rnd関数を使用しています。

Rnd関数はあらかじめ定められた乱数テーブルにしたがい乱数を返すらしいので、

上記コードを使って乱数テーブルを初期化することで、

常にランダムな数値を設定できるようにしています。

 

長々と書きましたが、Rnd関数で返される数値が一定のパターンにはまらないようにするために必要ということです。

 

これはマス目内のランダムな位置(セル番地)を設定するために行っている処理です。

例えば、難易度上級であればマス目内で取りうる行番号・列番号はそれぞれ以下のとおりになります。

行番号:9~24

列番号:9~38

 

上記コードではRnd関数を使うことによって、

取りうる行・列番号のうちのいずれかの数字を取得しています。

(上記例でいえば行番号は9~24のいずれか、列番号は9~38のいずれか)

 

マス目に爆弾を設置する処理です。

まず、先ほどRnd関数を使って設定した、マス目内のランダムな位置が空白であるかを確認します。

空白であるならば、その位置の値を爆弾マークにします。

 

Rnd関数で設定した位置が空白か、という条件は入れなくても問題ないと思いますが、

入れないと、すでに爆弾マーク設置した位置に、再度爆弾マークを設置するケースが出てきますので、

繰返処理の回数が多くなる可能性があると思います。

そんなわけで、処理回数を極力減らすためにも上記条件を入れてます。

 

マス目内に設置された爆弾の個数をカウントするコードです。

COUNTIF関数を使って爆弾の個数をカウントしています。

 

Excelで通常使用するような関数(SUMとかVLOOKUPとか)もマクロ内で使用することができます。

使用するには、"WorksheetFunction"というコードを記載すればOKです。

記載すると使用できる関数のリストが表示されますのでそこから選べばよいです。

(もちろん直接手で記載しても問題ありません)

 

以上で爆弾を設置するマクロのコード解説を終わります。

 

4.特に重要なコード

これまで解説してきたコードの中で、マインスイーパーの挙動を実現するために、

特に重要なコードについて、繰り返しになりますが触れておきたいと思います。

 

2.で触れた必要条件別にコードを紹介します。

 

・マス目内のランダムな位置を取得する

Rnd関数を使って、マス目内の取りうる行・列番号をランダムに生成しています。

 

・規定個数の爆弾を設置する

繰返処理Do~Loopを使い、終了条件を「マス目内の爆弾数=規定個数」とすることで、

規定個数の爆弾が設置されるまで爆弾を設置する処理を繰り返し行っています。

 

・設置位置は常にランダムである

Randomizeで乱数テーブルを初期化することで、

Rnd関数で生成される乱数が一定のパターンにならないようにしています。

そうすることで、Rnd関数を使って設定する行・列番号が常にランダムになるようになっています。

 

5.おわりに

今回は爆弾を設置するマクロのコードについて解説しました。

次回は数字を設置するマクロについて解説したいと思います。

ではまた。

マクロで作ったマインスイーパーの解説 詳細編 ゲーム画面を設定する

どうもこんにちは。

 

マクロで作ったマインスイーパーのコード解説をしていきます。

今回はゲーム画面を設定する編です。

マインスイーパーのゲーム画面(下図)を設定するマクロになります。

 

では内容に入っていきましょう。

 

 

1.コードの内容

まずは、実際に記述したコードをご紹介します。

長いので一つ一つ内容を確認したい方は読み飛ばしてもらって大丈夫です。

2.各コードの解説

では上で紹介したコードについて一つずつ解説していきたいと思います。

 

これはワークシート全体をクリアするコードです。書式・値すべてクリアされます。

 

これは難易度別に異なる部分の初期設定です。

初級(e)、中級(n)、上級(h)の3つのケースに分けて処理を記述しています。

条件分岐後のそれぞれのコードの内容は以下の通りです。

・bottom_r=・・・:マス目の最下行の設定

・rightedge_c=・・・:マス目の右端列の設定

・Cells(4,9)~Cells(4,11).Value・・・:爆弾カウントの表示の初期設定
(初級=010、中級=040、上級=099)

・start_b=・・・:爆弾の初期個数の登録

 

これは各難易度で共通部分の初期設定です。

それぞれのコードの内容は以下のとおりです。

・icon_b=・・・:icon_bの値に"💣"を登録

・icon_f=・・・:icon_fの値に"🏴"を登録

・t=0:経過時間(t)の初期値(0)を登録

 

画面更新を停止するコードです。

これを記述することでマクロの処理速度が向上します。

また、マクロ実行時にすべての書式が一度に変わるように見えます。

 

オブジェクト(操作対象となるもの)のコード記述を簡略化するために使用するコードです。

これを記述することでこれ以下のコードは、

常に「Worksheets("ms").」が記述されているものと扱われます。

 

シート内のセルの書式を変更するコードです。

ゲーム画面のイメージになるようにセルの幅や背景色等の書式を変更しています。

参考までにゲーム画面のイメージを再掲します。

 

使用しているコードの処理内容は以下の通りです。

・ColumnWidth:列の幅を設定する

・RowHeight:行の高さを設定する

・Interior.ColorIndex:セルの背景色を設定する。なお、2は白色です。

・BorderAround:外枠罫線を設定する。各引数の内容は以下のとおり。

  LineStyle=罫線の種類を決定。1は実線。

  Weight=罫線の太さを決定。2は極細線。

  ColorIndex=罫線の色を決定。上ではRGBで設定したかったため省略。

  Color=罫線の色を決定。RGBで任意の色に設定可。上では灰色。

  ThemeColor=罫線の色を決定。上では省略。

・MergeCells:セルを結合する

Value:セルの値を設定する

 

マス目の外枠部分に" "を入力する処理です。
(なお、このコードではマス目部分も含めて" "が入力されますが、
後のコードでマス目部分の値をクリアするので、外枠部分にだけ残ります)

 

これは空白マスを開いたときの動作がうまく働くようにするために行っています。

空白マスを開いたときの動作では、そのマスの周囲にあるブランクマスを検索する処理を行いますが、

マス目の外枠部分に何も値が入力されていないと、外枠部分まで開く対象に加えられてしまうので、

上記処理を施して外枠部分が検索に引っかからないようにしているのです。

空白マスを開く動作を解説するときにまた詳しく説明します。

 

マス目部分の書式を設定するコードです。

With内の処理の内容は以下の通りです。

・ClearContents:セルの値をクリアする

・Borders.LineStyle:格子罫線を引く。イコールの部分で罫線の種類を決定。
上では実線(xlContinuous)

・Borders.ColorIndex:罫線の色を決定する

 

・Interior.Pattern:背景色のグラデーションを行う

・Interior.Gradient.Degree:グラデーションの角度を決定

・Interior.Gradient.ColorStops.Add(0).Color:グラデーションの第1色の色を決定

・Interior.Gradient.ColorStops.Add(1).Color:グラデーションの第2色の色を決定

⇒マス目にグラデーションカラーを施しているのは、
それがマインスイーパーのマスが隠れた状態のデザインに近しかったからです。

・HorizontalAlignment:中央ぞろえにする(行方向)

⇒マスに配置される爆弾や数字などの表示位置の調整のためです。

・Font.Size:フォントの大きさを決定

・Font.Bold:フォントを太字にする

・NumberFormatLocal:セルの値の表示形式を決定する

⇒表示形式を";;;"にすると、そのセルに値を入力しても画面上その値が見えない状態になります。

なので、各マスの値に爆弾や数字が入力されたとしても、

上記表示形式にしておけば画面上は見えません。

マインスイーパーを再現するのに適切かと思いましたのでこれを採用しました。

なお、注意点は画面上見えなくても、そのセルを選択状態にすると入力されている値が数式バー上に表示されてしまうことです。

そのため、ネタバレ防止のためにマス目のセルを選択できないようにする処理が必要になります。

 

マス目以外の部分の書式を設定するコードです。

処理内容は上で触れたものと同じですのでここでは割愛します。

なお、オブジェクトの指定にあたり"Union"というコードを使用しています。

これを使えば複数の独立したセル範囲を指定することが可能です。

 

シートの表示倍率を変更するコードです。

ゲーム画面を見やすいサイズにするための処理です。
(40%は私のPCにとって見やすいサイズであり、使用環境によってサイズは異なるかもしれません)

 

先ほどマス目の表示形式の設定のところで触れた、ネタバレ防止のための処理です。

この処理を施すと選択状態にできるセル範囲をA1に限定することが可能です。

 

画面更新を再開するコードです。

上で触れた画面更新停止と対になるコードです。

 

以上、長くなりましたがコード解説を終わります。

 

3.マインスイーパー再現に重要なコード

ここでは上記で解説したコードの中でも、マインスイーパーを再現するために特に重要と考えられるコードは何かをまとめます。

ここさえ押さえておけばOKというポイントのまとめです。

マインスイーパーの挙動別にコードを紹介していきたいと思います。

 

・爆弾や数字を見えない状態にする

⇒「NumberFormatLocal = ";;;"」を設定する!

マス目部分の書式設定で紹介していますので詳細はそちらをどうぞ)

⇒マス目が選択されないようにスクロールエリアを限定する!
 「Worksheets("").ScrollArea = XXX」

 

・空白マスを開いたとき周囲にある空白マスをすべて開く

⇒この挙動を再現するために下準備として、外枠部分に" "を入力する!
 「Range(XXX).Value = " "」

 

長々と解説してきましたが、初期設定の中で特に重要なものは上記のみです。

正直、他のコードは適当でOKだと思います。

 

4.おわりに

今回はゲーム画面を設定するコードについて解説しました。

書式設定がほとんどですので、処理内容自体は単純でわかりやすいものが多かったかと思います。

 

次回はマス目に爆弾を設置するコードについて解説したいと思います。

ではまた。

 

マクロで作ったマインスイーパーの解説 全体像編

どうもこんにちは。

 

今回からマクロで作ったマインスイーパーの解説をしていきたいと思います。

どんな感じのものになっているかはこちらからご確認ください。

programminghajimetemita.hatenablog.com

 

細かい内容の解説に入る前に、

マインスイーパーのマクロの全体的な構造と、

実際のコードをご紹介します。

 

 

1.マインスイーパーの全体像

まずはマクロの全体像からです。

マクロの処理の流れをパワポにまとめましたのでご確認ください。

細かい図なのでわかりづらいかもしれませんが、

どんな処理をしているかざっくり言うと、以下のとおりです。

 

・図の一行目(Startから初期配置の記録まで)で、
ゲーム画面のマス目に爆弾と数字を設置

・図の三行目(operationからcnt_bombまで)で、
各種操作(マス目を開いたりフラグを設置したり)と
残爆弾数と経過時間のカウントを実施

・図の四行目でゲームオーバーになったか判定
⇒ゲームオーバーであれば全マスを開いてゲーム終了

・図の五行目でゲームクリアになったか判定
⇒ゲームクリアであればゲーム終了

・四行目、五行目の判定がFalseであれば、三行目の処理を繰り返す

 

どんな処理をしているか、大体ご理解してもらえたでしょうか?

次にこれらの実際のコードを紹介していきたいと思います。

 

2.マインスイーパーのコード

では実際に記述したコードの内容をご紹介します。

以下かなりボリュームが多いです。

興味がある部分のマクロだけ参照するなどして、適宜読み飛ばしてもらえたらと思います。

 

まずはマクロ内で使用した変数や定数について紹介します。

以下で紹介するマクロにはここで定義した変数・定数が出てきますので、

適宜参照しながら内容を見てもらえればと思います。

ここから各マクロのコードの内容の紹介です。

まずはマインスイーパーのメインのマクロです。

上で紹介したもののコード版と思ってもらえればよいかと思います。

次は「難易度選択」です。

ユーザーフォームは以下のように整えました。

OKボタンに登録したコードは以下の通りです。

次は「ms_setting」です。
以下のゲーム画面になるように書式を設定するマクロになります。
(以下は難易度上級に対応するものです)

コードの内容は以下の通りです。

次は「set_bomb」です。マス目内に爆弾を設置するマクロです。

次は「set_num」です。マス目内に爆弾に対応する数字を設置するマクロです。

次は「operation」です。キーボード操作に応じてゲーム内の処理を行うマクロです。

次は空白セルを開いたときの動作を制御する「act_blank」です。

全体像の中では触れていないマクロになります。

ただ、「operation」のパーツになっているマクロですので、ここで併せて紹介しておきます。

次は空白セルを開いたときに周囲にある空白セルを登録する「rec_blank」です。

これも全体像の中では触れていないマクロですが、

上で紹介した「act_blank」のパーツになっているマクロですのでここで紹介します。

次は「cnt_time」です。経過時間をカウントするマクロです。

次は「cnt_bomb」です。残爆弾数をカウントするマクロです。

ここからは関数をご紹介します。

まずは設置した数字のフォントの色を制御する「SetNumColor」関数です。

全体像の中で触れていない関数ですが、「set_num」マクロのパーツとして働く関数になっています。

次は「CheckGameOver」です。ゲームオーバーを判定する関数です。

最後に「CheckGameClear」です。ゲームクリアを判定する関数です。

 

以上、コードの内容のご紹介でした。

次回以降、これらのコードを詳しく解説していきたいと思います。

 

3.おわりに

今回はマクロで作ったマインスイーパーの全体像についてご紹介しました。

このマクロを作るのにかかった時間は約35時間でした。

空白セルを開けたときの挙動を再現するコードを組むのがかなり難しく、

ほぼそのコードの内容を考えるのに時間を費やしました。

 

次回はゲーム画面の書式設定を行う「ms_setting」について解説します。

ではまた。

エクセルのマクロでマインスイーパーを作ってみた。

どうもこんにちは。

 

またエクセルのマクロでゲームを作ったので、

その内容を紹介していこうと思います。

 

今回作ったゲームはマインスイーパーです。

以下はゲーム開始前の画面です。

 

左上のGame Startボタンを押すと難易度選択画面に遷移します。

 

難易度を選択しOKを押すと、難易度に応じたゲーム画面が表示されます。

ゲーム画面左上の赤字が爆弾の個数、右上の赤字がゲーム開始からの経過時間を表します。

 

任意のマス上でctrlボタンを押すと、そのマスを開くことができます。

 

空白のマスを開くと、数字マスに行き当たるまで、

周囲にある空白マスがオープンされます。(下図の左下部分)

 

F4ボタンを押すとフラグを設置することができます。

再度、F4ボタンを押すことで設置したフラグを解除できます。

なお、フラグを設置することで爆弾のカウントが減っていきます。

 

数字マスの周囲のマスにその数字と同数のフラグが設置されているときに、

その数字マス上でctrlボタンを押すと、その数字マスの周囲のマスがすべてオープンされます。

 

すべての爆弾にフラグを設置するとゲームクリアです。

ゲームクリアのメッセージとクリアタイムが表示されます。

 

爆弾マスをオープンするとゲームオーバーです。

すべてのマスがオープンされ、ゲームオーバーのメッセージが表示されます。

 

いかがでしょうか?

マインスイーパーぽくできあがってますよね?

 

マインスイーパーのイメージはお伝え出来たかと思いますので、

次回以降、これをどうやって作ったのかに焦点をあてて解説していきたいと思います。

 

ではまた。

VBAテトリス 詳細編 ゲーム中に音楽を流す

どうもこんにちは。

 

今回もマクロで作ったテトリスのコード解説をしていきます。

テトリスがどんな感じのものになっているかは以下リンクからご確認ください。

programminghajimetemita.hatenablog.com

 

今回の内容はゲーム中に音楽を流す方法になります。

では内容に入っていきましょう。

 

 

1.ゲーム中に音楽を流すコード

ゲーム中に音楽を流すコードですが、VBAの枠外の力を借りて行います。

具体的には、「mciSendString」という関数を利用します。

この関数の利用により任意の音楽ファイルの再生等を行うことができるようになります。

 

この関数の使い方は以前の記事でキーボードが押されたことを検知する関数を利用したときと似たような感じになります。

programminghajimetemita.hatenablog.com

 

まずは、当該関数をマクロ内で利用できるように、

コードの冒頭で以下の宣言を行います。

 

Private Declare Function mciSendString Lib "winmm.dll" Alias "mciSendStringA"
(ByVal lpstrCommand As String, ByVal lpstrReturnString As String,
ByVal uReturnLength As Long, ByVal hwndCallBack As Long) As Long

 

書かれているコードの内容は正直わかりません。笑

内容はわかりませんが、これを書いておけばmciSendString関数は確かです。

詳しい内容が知りたい方はぜひググってみてください。

 

音楽を再生するときは以下のようなコード記述となります。

 

        Call mciSendString("Play " & 音楽ファイルのアドレス, "", 0, 0)

 

赤字部分は自分が流したい音楽ファイルの保存先のアドレスを記載してください。

 

音楽を停止するときは以下のようなコード記述となります。

 

     Call mciSendString("stop " & 音楽ファイルのアドレス, "", 0, 0)

 

赤字部分は再生時と同様、停止したい音楽ファイルの保存先のアドレスを記載してください。

 

以上で音楽を流すために利用するコードの解説を終わります。

次はマクロで作ったテトリスの中でこれをどう活用したかについて解説していきます。

 

2.自作テトリスで実際に記載したコード

自作テトリスの中では、以下の2つの目的で音楽を流すコードを利用しました。

・ ゲーム開始からゲーム終了までゲーム用の音楽を繰り返し再生する

・ ゲーム終了時にゲーム用の音楽を停止し、終了用の音楽を再生する

順に解説していきたいと思います。

 

・ ゲーム開始からゲーム終了までゲーム用の音楽を繰り返し再生する

音楽を再生するのに使うコードは1.で紹介したコードになります。

ここで、当該コードでは一度再生するのみで繰り返し再生は行えません。

ということで、いかにして繰り返し再生を行わせるかがポイントになります。

 

私が作ったプログラムでは、テトリミノの落下に関する繰り返し処理の中に

音楽を再生するコードを入れることで実現しました。

こうすることで、テトリミノが一マス落下するごとに音楽再生コードが実行されるので、

音楽の再生が終了してから再度再生するまでのタイムラグをかなり短くすることができます。

 

なお、音楽再生中に再生コードが実行されても、

再生中の音楽が中断されて最初から再生される、

といったような挙動にはなりません。

 

なので、音楽再生⇒終了⇒再度、音楽再生⇒終了・・・という感じで、

繰り返し再生が行うことができます。

 

・ ゲーム終了時にゲーム用の音楽を停止し、終了用の音楽を再生する

これはゲームオーバーの演出を行うマクロの中に、

ゲーム用の音楽を停止するコードと終了用の音楽を再生するコードを組み込みました。

コードの内容は1.で紹介したとおりです。

実際のコードは以下のようになります。

 

    Call mciSendString("stop " & sound1, "", 0, 0)
    Call mciSendString("Play " & sound2, "", 0, 0)

 

※ sound1はゲーム用の音楽ファイルのアドレス、
sound2は終了用の音楽ファイルのアドレスを指す変数

 

以上で利用方法の解説を終わります。

 

3.おわりに

今回はゲーム中に音楽を流す方法について解説しました。

今回の解説でテトリスのコード解説は終了となります。

 

これまで長々とテトリスの解説を行ってきましたが、いかがでしたでしょうか?

ご興味をもってもらえ、自分でもできそうだなという感覚になってもらえていたらうれしい限りです。

 

次回からはマクロで作った別のゲームのコード解説を行っていこうと思います。

ではまた。

VBAテトリス 詳細編 ゲームオーバーの判定・演出

どうもこんにちは。

 

今日も今日とて、マクロで作ったテトリスの解説をしていきます。

 

どんな感じのものなのかイメージを確認したい方は以下リンクからどうぞ。

programminghajimetemita.hatenablog.com

 

今回の内容はゲームオーバーの判定・演出についてです。

 

 

1.テトリスの挙動

まずはいつも通りテトリスの挙動を考えてみましょう。

テトリスではどのような状態になるとゲームオーバーと判定されるかというと、

ブロックを動かすことができなくなった状態になったときです。

 

もう少し具体的にいうと、初期表示される位置がブロックで埋まってしまった状態です。

このような状態になると、次のテトリミノを表示しようにもできませんから、

ゲームが続行できないのでゲームオーバーということですね。

 

で、ゲームオーバーと判定されると、以下の演出が行われます。

(なお、これはテトリスミニの挙動です)

 

・下の行から一行目まで、一行ずつブロックの揃った行が表示されていく

・上の演出によりゲーム画面全体がブロックで埋まった後、

一行目から最下行まで、一行ずつブロックの揃った行が消えていく

 

言葉だけではわかりづらいと思いますので以下にイメージを載せておきます。

(これでもわかりづらいかもしれませんが。。。)

 

まず、下から一行ずつブロックの揃った行が表示されていきます。

一行目に到達後は一行目から順にブロックの揃った行が消えていきます。

最後はすべてのブロックが消えた状態になります。

 

テトリスの挙動の解説は以上になります。

次はこれを踏まえてどういった処理が必要になるかを考えます。

 

2.必要な処理

まずはゲームオーバーの判定です。

先ほど述べた通り、

初期表示される位置にブロックが埋まっている状態

がゲームオーバーの条件になります。

 

初期表示位置にブロックがあるわけですから、

ゲーム画面一行目の状態が、

□□□■■■■□□□

例えばこんな状態になっているとき、ゲームオーバーと判定できればよいですね。

(□は空白のマスと考えてください)

 

「こんな状態」ではコード化が難しいのでこれを言語化しますと、

「一行目のセル範囲の背景色に無色と黒色が混在している状態」と言い表すことができます。

(なお、これは私の解釈であり、他の解釈もあり得ると思います。

唯一の解ではないという点ご留意ください)

 

この無色と黒色が混在したセル範囲について、

ColorIndexがどうなるかというと、「Null」になります。

 

ということで、これを利用して、

一行目のColorIndexが「Null」であるとき、ゲームオーバーと判定する、

という処理ができれば、テトリスの挙動を再現することができます。

 

ちなみに、この判定はブロックが壁やほかのブロックに接地した時点で行われるので、

ゲーム続行可能なときは常に一行目が空白(無色)になり、

ColorIndexが「Null」にならないので、上記判定でイメージ通り動作させることができます。

 

次に、ゲームオーバーの演出です。

まずは下から一行ずつブロックの揃った行にしていけばよいので、

繰り返し処理を使ってブロックの揃った行にする処理を繰り返せばOKですね。

なお、ブロックの揃った行にするのはセルの書式を調整すればよいです。

 

上からブロックの揃った行を消していく演出についても、

上記と同様に、「行の消去(=セルの書式調整)を繰り返す」ことでOKです。

 

以上、必要な処理について解説しました。

最後にコードの内容に入りましょう。

 

3.ゲームオーバーの判定・演出を行うコード

まずはゲームオーバーの判定に関するコードです。

必要な処理で述べた通り、

一行目のColorIndexが「Null」になったらゲームオーバーと判定したいので、

その状態になったときに「True」を返す関数を作りました。

 

Function checkgame() As Boolean
    If IsNull(Range(Cells(start_r, leftedge_c), Cells(start_r, rightedge_c)).Interior.ColorIndex) Then
        checkgame = True
    End If
End Function

 

IsNull()の部分で、カッコ内に記述した内容がNullかどうかを判定しています。

繰り返しになりますが、Nullと判定されれば「True」を返す仕組みになっています。

 

次にゲームオーバーの演出のコードです。

必要な処理は「セルの書式調整」+「繰り返し」ですので以下のようになります。

 

   Sub gameover()
    For r = end_r To start_r Step -1
        With Range(Cells(r, leftedge_c), Cells(r, rightedge_c))
            .Interior.ColorIndex = 1
            .Borders.LineStyle = xlDouble
            .Borders.ColorIndex = 2
        End With
        Application.Wait [Now() + TimeValue("00:00:00.2")]
    Next r
    For r = start_r To end_r
        Range(Cells(r, leftedge_c), Cells(r, rightedge_c)).ClearFormats
        Application.Wait [Now() + TimeValue("00:00:00.3")]
    Next r
End Sub

 

上側のForがブロックの揃った行の表示、

下側のForがブロックの揃った行の消去のコードになります。

 

上側のコードでWithの中に記載しているのが、

ブロックの書式になります。

繰り返し処理は下の行から上の行に向かって行いたいので、

カウンタ変数の設定を「最下行 To 一行目 Step -1」としています。

 

下側のコードはブロックの消去に関するコードですが、

単純にClearFormatsで書式のクリアを行うことで再現しています。

 

なお、いずれのコードでもApplication.Waitというコード(指定秒数処理中断する)

を使っていますが、

これは演出がきれいに見えるようにするためです。

処理中断時間を設けないと、テトリスミニの挙動っぽくならなかったので、

実際の動きと見比べつつ、中断時間を調整しました。

 

以上、判定と演出のそれぞれのコードについて解説しました。

これらを組み合わせると以下のようなコードになります。

 

        If checkgame = True Then
            Application.ScreenUpdating = True
            Application.Calculation = xlCalculationAutomatic
            Call gameover
            Exit Do
        Else
            ・・・
        End If

 

checkgameがTrue、すなわち、

ゲーム画面一行目の一部にブロックが埋まれば(ColorIndex=Null)、

Then以下のコードが実行されます。

 

Then以下のコードではgameoverを呼び出しているので、

当該マクロの実行によりゲームオーバーの演出が流れます。

 

なお、この処理は、

テトリミノが初期位置に表示される⇒接地するまで下に落ちるの繰り返し処理

の中に組み込まれています。

そして、ゲームオーバーであるということは、

その繰り返し処理を終了する必要がありますので、

gameoverの呼び出し後、Exit Doにより繰り返し処理を終了させています。

 

以上でゲームオーバーの判定・演出の処理のコード解説を終わります。

 

4.おわりに

今回はゲームオーバーの判定・演出について解説しました。

今回紹介したコードをもってテトリスはほぼ完成です!

ゲームとして成り立つ内容になってます。

 

ただ、ゲーム中無音です。さみしいですね。

やっぱりBGMがあった方がゲームっぽいですよね。

 

ということで、次回はゲーム中に音楽を流すコードについて解説します。

 

ではまた。

VBAテトリス 詳細編 SCORE等を計算する

どうもこんばんは。

 

エクセルのマクロでこんな感じのテトリスを作りました。

programminghajimetemita.hatenablog.com

 

今回もこのテトリスのコードについて解説していきます。

今回はブロックを消去したときにSCORE等を計算する処理に関するコードです。

 

 

1.テトリスの挙動

毎度のことですが、まずはテトリスの挙動について触れておきます。

私が参考にしたのはテトリスミニの挙動ですので、

以下の内容はそれを指しているものとご理解ください。

 

テトリスではブロックの揃った行を消去すると、

その行の数に応じてSCOREを計算し、

計算後のSCOREが画面に表示されます。

 

ブロックの消去により変動する要素は、

SCORE以外にもLINESとLEVELというものがあります。

 

LINESは消去した行数をカウントするものです。

4行消去⇒LINES=4、3行消去⇒LINES=7、といったように、

ブロックの揃った行が消去される度に、消去した行数が加算されていきます。

 

LEVELはLINESの値に応じて上昇する変数になります。

LINESが10増えるごとにLEVELが1増えていきます。

なお、このLEVELの値によってテトリミノの落下スピードが変わります。

 

上記2つの要素についても、SCOREと同様に、

消去のたびに計算が行われ、計算結果がゲーム画面に表示されます。

 

さて、再度SCOREの計算の話に戻ります。

消去した行数に応じ計算する、とは具体的にどんな計算をしているのかについてです。

 

SCOREは、一度に消去した行数と消去時のLEVELによって以下のとおり計算されます。

1行の場合:10×LEVEL

2行の場合:30×LEVEL

3行の場合:50×LEVEL

4行の場合:80×LEVEL

 

以上、SCORE等に関してのテトリスの挙動についてでした。

次はこれらをもとにどういう処理が必要になるかを考えます。

 

2.必要な処理

先ほど解説したテトリスの挙動を踏まえると、

必要な処理は大まかにわけて以下の2つです。

 

・値を計算する

・計算した値を画面に表示する

 

それぞれ詳しくみていきましょう。

 

・値を計算する

SCORE、LINES、LEVELのそれぞれの要素について、

一定のルールに従って値を計算する必要があります。

 

これは単純に変数を準備して計算してやればよいですね。

それぞれの計算ルールはテトリスの挙動で解説したとおりですが、

あらためて以下に記述しておきます。(ざっくりですが)

 

SCORE:消去した行数に応じた点数×LEVEL

LINES:消去した行数

LEVEL:消去した行数が10に達する度に1加算

 

なお、いずれの要素も累計値になりますので、

実際にコードを書く際には結果が累計値になるようにしておく必要がある点、

ご留意ください。

 

・画面に表示する

私が作ったテトリスの画面は以下のようなデザインになっています。

 

画面を見ていただいてわかるとおり、

各要素を表示する箇所がありますので、

ここに計算結果を表示すればOKです。

 

表示方法は簡単で、各要素が表示されているセルの値を、

計算後の変数の値に変更するのみです。

 

処理が明確になったところで次はコードの内容について考えましょう。

 

3.SCORE等を計算するコード

まず、計算に使用した変数を紹介します。

 

計算には4つの変数を使用しました。

score、tmp_line、line、levelの4つです。

 

変数の名前のとおりで、

scoreはSCOREの、lineはLINESの、levelはLEVELの計算を行う変数です。

いずれもゲーム開始から終了までの累計値を表すものになります。

 

残りのtmp_lineというのは、消去時の行数をカウントする変数になります。

 

SCOREは消去時の行数に応じて計算される要素ですので、

行数については累計値のみでなく、消去時の値も計算する必要があります。

そのためにこの変数が必要ということですね。

 

次に、各変数の値を計算するコードについてです。

scoreについてはテトリスの挙動で解説した計算式を使って値を計算します。

消去時の行数に応じて計算式が変わりますが、そこは条件分岐で対応すればOKです。

 

    Select Case tmp_line
        Case 1
            score = score + 10 * level
        Case 2
            score = score + 30 * level
        Case 3
            score = score + 50 * level
        Case 4
            score = score + 80 * level
    End Select

 

繰り返しになりますが、scoreは累計値とすべきものですので、

計算前のscoreに消去時に獲得するscoreを加算することで累計値としています。

 

LINESについては消去した行数の累計値を計算すればよいので、

コードは以下のようになります。

 

    line = line + tmp_line

 

ちなみにtmp_lineはどのように計算しているかというと、

ブロックの消去の処理を行うときについでに計算しています。

 

前回の記事で、未消去の行を下に落とす、という処理を解説しましたが、

その中で計算を行っています。コードは以下のとおりです。

 

    Application.ScreenUpdating = False
    Application.Calculation = xlCalculationManual
    For r = end_r To start_r Step -1
        If checklinewhite(r) = True Then
            tmp_line = tmp_line + 1
            Range(Cells(start_r, leftedge_c), Cells(r - 1, rightedge_c))
    .Copy Destination:=
    Range(Cells(start_r + 1, leftedge_c), Cells(r, rightedge_c))

            r = r + 1
        End If
    Next r

 

上記処理は消去行の数だけ処理が行われますので、

処理のたびに1加算すれば消した行数になるというわけです。

 

なお、tmp_lineの計算後、何も手を加えなければ、

計算結果が変数に残り続けてしまいますので、

ブロック消去の一番初めの処理として、

tmp_lineの値をゼロにするコードを入れています。

tmp_line = 0)

 

さて、最後にLEVELの計算です。

LEVELは消去行数が10増えるごとに1増えていくものと解説しました。

 

LEVELは1からスタートしますので、

LINESが10になったらLEVELは2、20になったらLEVELは3という感じです。

また、LINESが1~9のときLEVELは1、11~19のときLEVELは2とも言えますね。

 

このように考えると、

LINESの値を10で割った値(少数点以下切り捨て)に1を足せば、

出したい値にすることができそうです。

 

例えば、

LINESが5の場合:5 ÷ 10 + 1
        = 0.5 + 1
        = 0 + 1 = 1

LINESが10の場合:10 ÷ 10 + 1
          = 1 + 1 = 2

LINESが11の場合:11 ÷ 10 + 1
          = 1.1 + 1
          = 1 + 1 = 2

という感じで、思ったような結果になりましたね。

あとはこれをコード化すればよいわけです。

実際に作ったコードは以下の通りです。

 

    level = Int(line / 10) + 1

 

Intを使えば計算結果が正の値であれば必ず小数点以下を切り捨ててくれます。

ワークシート関数のRoundDownを使っても可能かと思いますが、

こちらの方がコードの内容がすっきりしていてシンプルでわかりやすいと思ったので、

これを採用しました。

 

各要素を計算するコードの解説は以上です。

 

あとは画面に表示するコードですが、

セルの値を変数に格納された値とすればよいので、

表示したいセル.Value = 変数(score, line, level)でOKです。

 

ここまでのコードをまとめると以下のようになります。

 

Sub calculatescore()
    'SCOREの計算
    Select Case tmp_line
        Case 1
            score = score + 10 * level
        Case 2
            score = score + 30 * level
        Case 3
            score = score + 50 * level
        Case 4
            score = score + 80 * level
    End Select
    Cells(18, 21).Value = score

    'LINESの計算
    line = line + tmp_line
    Cells(22, 21).Value = line

    'LEVELの計算
    level = Int(line / 10) + 1
    Cells(13, 21).Value = level
End Sub

 

以上でコードの解説を終わります。

 

4.おわりに

今回はSCORE等を計算するコードについて解説しました。

これまでの内容と比べると簡単な内容だったかと思います。

次回の内容もそれほど難しくない内容ですので、

テトリス完成までもうひと踏ん張り頑張りましょう。

 

ではまた。