|

|
|
 |
6.1 自機をキーボードで操作 |
 |
|
|
|
|
|
画面上のキャラクタが動く理屈はエクセルマクロTips〜ゲーム篇〜の2.4 パターンを移動する方法に書いてある通り、貼り付け先の横位置を常に変化させるがポイントです。これを応用し、ボタンが押されているときだけ貼り付け先の横位置を変化させるようにすれば、矢印ボタンで左右に移動することができます。
それと、キーボードの特定のボタンが押されているかを調べるときは、APIのGetAsyncKeyState関数を使います。キーボードのボタンにはそれぞれ決まった番号が割り当てられており、GetAsyncKeyState関数で指定した番号のボタンが押されているときは0以外、押されていないときは0が関数の戻り値に返ってきます。
なお、エクセルマクロTips〜ゲーム篇〜の3.1 キーボードからの入力を判定するでは、GetAsyncKeyState関数の使い方とキーコード一覧に加えて、ボタンが押されているときにキャラクタの移動する方法についても触れていますので、参考までにどうぞ!
|
|
|
|
|
|
| Sheet1(ゲーム)のマクロ「(General)(Declarations)」への変数追加 |
|
|
|
|
最初に(General)(Declarations)へ変数と定数をいくつか定義しておきます。
必要な変数は、自機の位置を表す変数lngMyShipX(Long型)と、自機のパターン(コピー元のRangeオブジェクト)を入れておくrngMyShip(Range型の変数)、それと矢印キーの番号を定義した定数です。これらの変数や定数は、今後あちこちのプロシジャから参照するので(General)(Desclarations)へ定義します。
矢印キーのコードを定数にしたのは、単純にプログラムを分かりやすくするためです。プログラム中で37と数値で指定するより、cstFKeyLeftと指定した方が「左ボタンの処理だな…」とすぐにわかるでしょ?なお、キーボードの番号についてはエクセルマクロTips〜ゲーム篇〜の3.1 キーボードからの入力を判定する/キーコード一覧を参考にしてください。
あとは、ゲームの状態を表す定数です。見たままですが、これについての詳しい話は以降の章で徐々に説明します。
★Sheet1(ゲーム)のマクロ「(General)(Declarations)」
Option Explicit
'エクセルスマイル★シューティングゲームを作ろう
'記述場所:ワークシート「ゲーム」
'記述箇所:(General)(Declarations)
Dim lngGameStatus as Long 'ゲームの状態
Dim lngMyShipX As Long '自機の横位置
Dim rngMyShip As Range '自機のパターン
Const cstFKeyLeft As Long = 37 '左ボタン
Const cstFKeyRight As Long = 39 '右ボタン
Const cstPlay As Long = 1 'ゲーム中
Const cstStageClear As Long = 2 'ステージクリア
Const cstGameOver As Long = 4 ' ゲームオーバー
Const cstDemo As Long = 8 ' デモ画面
|
※このマクロは、ワークシート「ゲーム」へ記述してください。
|
|
|
|
|
|
| Sheet1(ゲーム)のマクロ「prcMyShipMove」の作成 |
|
|
|
|
自機を左右に動かすための処理です。このマクロでは、左ボタン押されているときはlngMyShipXから1を引く(自機を左に移動)、右ボタンが押されているときはlngMyShipXへ1を足す(自機を右に移動)処理と、自機の描画処理(と言ってもコピペ)を行っています。
自機は左右に動作しますが、左端や右端に達したときはそれ以上移動できないようにする必要があります。
自機の横位置を表すlngMyShipXが示す部分はは図の通りですが、これを踏まえた上で自機が左に移動できるのはlngMyShipXが1より大きいときで、左ボタンの処理では自機が左へ移動できるならlngMyShipXから1を引きます。
同じように、自機が右に移動できるのはlngMyShipXが129未満のときで、右ボタンの処理では自機が右へ移動できるならlngMyShipXへ1を足します。
ちなみに、自機は縦には移動しません。そのため、縦位置は固定値で135〜142とします
あと、自機の描画のコピー元で使っているrngMyShipですが、この変数には自機のパターン(コピー元の範囲)が設定されています。自機の描画では、貼り付け先(Destination:=)のRangeで範囲指定(右下)を142,lngMyShipX+15としていますが、横位置は常に可変なので調整値(自機の場合は15)を足して範囲指定を行います。lngMyShipX〜lngMyShipX+15が横の範囲です。
ところで、「自機の幅が16なのになぜ15か」というと、例えばlngMyShipXが50のとき横は50〜65の16セル分の範囲が自機を描画するために必要な範囲です。もし、横位置の指定に自機の大きさをそのまま加算すると「50+16」なので50〜66の範囲を指定(17セル)することになってしまうため、「自機の幅-1」の値である15を指定するのです。
★Sheet1(ゲーム)のマクロ「prcMyShipMove」
Sub prcMyShipMove()
'エクセルスマイル★シューティングゲームを作ろう
'処理概要:自機の操作や描画を行う
'記述場所:ワークシート「ゲーム」
'左キーが押されている場合
If GetAsyncKeyState(cstFKeyLeft) <> 0 Then
'左端に達していない場合は自機の位置から1を引く
If lngMyShipX > 1 Then
lngMyShipX = lngMyShipX - 1
End If
End If
'右キーが押されている場合
If GetAsyncKeyState(cstFKeyRight) <> 0 Then
'右端に達していない場合は自機の位置へ1を足す
If lngMyShipX < 129 Then
lngMyShipX = lngMyShipX + 1
End If
End If
'自機の描画
rngMyShip.Copy _
Destination:=Range(Cells(135, lngMyShipX) _
, Cells(135 + 7, lngMyShipX + 15))
End Sub
|
※このマクロは、ワークシート「ゲーム」へ記述してください。
|
|
|
|
|
|
| Sheet1(ゲーム)のマクロ「prcAllInit」の作成 |
|
|
|
|
全体の初期設定(起動時の初期設定)をするための処理で、オブジェクトの作成やスコア、ハイスコアの設定など起動時に一度だけ行えばいいような初期設定や、その他の全体的な初期設定を行います。
全体の進行状態を表す変数lngGameStatusは、とりあえずcstGame(ゲームプレイ中)を設定しておきますが、最終的にはcstDemoに変更します。
なお、この処理はプロシジャprcGame(ゲームの主処理)から呼び出して使います。
★Sheet1(ゲーム)のマクロ「prcAllInit」
Sub prcAllInit()
'エクセルスマイル★シューティングゲームを作ろう
'処理概要:アプリケーション全体の初期設定を行う
'記述場所:ワークシート「ゲーム」
'ゲームの状態を設定
lngGameStatus = cstPlay
'自機のパターンを設定
Set rngMyShip = Range(Cells(201, 1), Cells(208, 16))
'ゲーム画面の初期化
Call prcScreenInit
End Sub
|
※このマクロは、ワークシート「ゲーム」へ記述してください。
|
|
|
|
|
|
| Sheet1(ゲーム)のマクロ「prcGameInit」の作成 |
|
|
|
|
ステージ毎の初期設定処理をするための処理で、自機の初期位置や状態、敵の初期位置や状態など、ステージごとに初期化が必要な変数の設定を行います。
この処理は、プロシジャ「prcGame」から呼び出されますが特に変わったことはしていません。ちなみに、自機の位置ははステージ開始毎に初期処理をする必要があるためココで行っています。
★Sheet1(ゲーム)のマクロ「prcGameInit」
Sub prcGameInit ()
'エクセルスマイル★シューティングゲームを作ろう
'処理概要:ステージ毎の初期設定を行う
'記述場所:ワークシート「ゲーム」
'自機の横位置設定
lngMyShipX = 1
'ゲーム画面の初期化
Call prcScreenInit
End Sub
|
※このマクロは、ワークシート「ゲーム」へ記述してください。
|
|
|
|
|
|
| Sheet1(ゲーム)のマクロ「prcGameMain」の作成 |
|
|
|
|
ゲームの主制御処理をする処理で、画面の初期化と変数の初期化、自機のRangeオブジェクトの設定などの初期処理の後に、ゲームの主制御処理を行います。
ゲームの主制御処理はDo〜Loopの部分で、この中でプロシジャ「prcMyShipMove」を呼び出し自機の移動処理を行っています。なお、このプロシジャのループの終了条件は、ゲームの進行状態(lngGameStatus)がステージクリア(cstStageClear )またはゲームオーバー(cstGameOver)になるまでですが、まだその条件を成り立たせる処理が無いので永久です。
でも、安心してください。Escキーを押すことで処理を止めることができます。
★Sheet1(ゲーム)のマクロ「prcGameMain」
Sub prcGameMain()
'エクセルスマイル★シューティングゲームを作ろう
'処理概要:ゲームの主制御処理
'記述場所:ワークシート「ゲーム」
'ゲームの初期設定
Call prcGameInit
'主処理(ステージクリアかゲームオーバーになるまで実行)
'強制終了はEscキーを押す
Do Until lngGameStatus = cstStageClear or lngGameStatus = cstGameOver
'自機の移動処理を呼び出す
Call prcMyShipMove
Loop
End Sub
|
※このマクロは、ワークシート「ゲーム」へ記述してください。
|
|
|
|
|
|
| Sheet1(ゲーム)のマクロ「prcGame」の作成 |
|
|
|
|
全体を制御するための処理です。最終的にはこの処理でゲームを実行するか、デモ画面を実行するか、ゲームオーバー処理を行うなどの全体の制御を行いますが、今のところは自機の移動だけを行えれば良いです。というわけで、全体の初期設定(prcAllInit)とゲーム主制御処理(prcGameMain)の呼び出しのみを行っています。
ちなみに、このプロシジャでのループは永久に終了しません。つまり、永久ループってわけです。でも、安心してください。Escキーを押すことで処理を止めることができます。
★Sheet1(ゲーム)のマクロ「prcGame」
Sub prcGame()
'エクセルスマイル★シューティングゲームを作ろう
'処理概要:全体の主制御処理
'記述場所:ワークシート「ゲーム」
'変数の初期設定
Call prcAllInit
'主処理(永久にprcGameMainを呼び続ける)
'終了はEscキーを押す
Do Until False
'ゲームの主制御処理の呼び出し
Call prcGameMain
Loop
End Sub
|
※このマクロは、ワークシート「ゲーム」へ記述してください。
|
|
|
|
|
|
|
|
|
|
サンプルのコードを全て定義したら、Sheet1のプロシジャ「prcGame」を実行しましょう。実行する際は、VBエディターからの実行ではなく、エクセルのツールバーにある (マクロの実行)ボタンを押し、マクロの一覧で「Sheet1.prcGame」を選択しましょう。
実行すると、キーボードの左右のボタンで自機を移動することができます。ちなみに、何の小細工もしていないのでかなり動きが速いです。てゆーか速すぎると思いますが、後でなんとかするので今は気にしないでください(笑)
なお、実行すると永久ループと同じような状態になるのでタダでは停止できません。 (マクロの停止)ボタンが押せないのです。
でも、安心してください。Escキーを押すことで処理を止めることができます。
|
|
|
|
|