5.2 迷路の中を歩き回る
突然ですが、迷路の中を歩き回るゲームがあったとします。壁を突き破って進む荒技(笑)が出来る場合をのぞき、通常は進みたい方向に壁があるときはそれ以上進むことができません。

このようなこと(壁があるか無いか)は人間なら画面を見ると一目で判断できますが、コンピュータはそうは行きません(笑)。というわけで、ココでは進みたい方向に壁があることを判断する方法の一例を紹介します。
サンプルのダウンロード
この章で使うサンプルです。こちらのサンプルファイルをダウンロードしてご利用ください。もちろん、ノートン・アンチウィルスでチェック済みのファイルです。

サンプルファイルをダウンロードしたら、Capter00502というマクロを実行してください。実行すると、迷路と主人公である何者かが表示され、矢印キーでその何者かを操作できます。なお、停止するときはESCボタンを押して下さい。
迷路のデータ
まずは、サンプルファイルのSheet2を見て下さい。01で迷路のような物が描かれていますが、これがこのネタの中心「迷路のデータに」なります。見ての通り、1が壁で、0が通路です。セルには、分かりやすいように条件付き書式が設定してあり、1を入れるとセルの背景色が茶色になり、0を入れると背景色が消えます。

サンプルを実行すると何者かを動かすことができますが、何者かを移動するときはこの迷路データを元にして移動の可否を判断しています。

例えば上に移動(↑ボタンを押す)したいときは現在地の一つ上が0(通路)であれば上に進む処理を行い、同じように右へ移動(→ボタンを押す)したいときは現在地の一つ右を参照し0(通路)であれば右へ進む処理を行う、というように各方向毎に進めるか進めないかをチェックします。


サンプルでは、迷路データを参照するときはワークシートを直接覗くのではなく、迷路データをいったんvarScreenという変数に保存し、varScreenを参照しています。

変数への保存は、次の処理です。Sheet1のprcInit()からSheet2のgetScreenを呼び出し、getScreenの戻り値(迷路データ)をvarScreenへ保存しています。なお、varScreenVariant型ですが、取得後は2次元配列(Dim varScreen(1 to 8, 1 to 8)と同じ)になります。

 ◆Sheet1のPrivate Sub prcInit()より抜粋
'迷路データの取得
varScreen = Sheet2.getScreen()

 ◆Sheet2のFunction getScreen() As Variant
Function getScreen() As Variant

    Dim tmpScreen As Variant

    'R1C1〜R8C8の範囲をtmpScreenに保存(配列になります)
    tmpScreen = Range(Cells(1, 1), Cells(8, 8))

    '取得した迷路データを戻り値に設定
    getScreen = tmpScreen

End Function
 ※この方法についてはエクセルマクロTips11.5 大量のデータを取り出す、書き込むを参照
初期設定(迷路の描画、自機の位置)
迷路データは自機の移動可否以外にも、ワークシート上へ迷路を描画するためにも使っています。変数varScreenの値を一つずつ取り出し、1であればワークシート上へレンガ模様を描画しますが、ポイントは迷路データ1コがワークシート上では縦8×横8の大きさになるという部分です。

例えばvarScreen(1, 1)はワークシート上のR1C1〜C8C8へ描画、varScreen(2, 2)はワークシート上のR9C9〜R16C16へ描画するように、迷路データから取り出すときに使ったインデックスの値(i、j)をワークシート上の該当する位置へ変換して描画しています。

自機の位置は、このような変換が面倒なので2種類持つようにしました。ワークシート上での位置を管理する変数lngXlngY、迷路データ上での位置を管理する変数lngSXlngSYです。

 ◆Sheet1のPrivate Sub prcInit()より抜粋
'迷路の描画
For i = 0 To 7
    For j = 0 To 7
        If varScreen(i + 1, j + 1) = 1 Then
         rngWall.Copy _
               Destination:=Range(Cells(i * 8 + 1, j * 8 + 1) _
                                , Cells(i * 8 + 8, j * 8 + 8))
        End If
    Next
Next

'自機キャラ位置の初期位置
lngX = 9
lngY = 9

'自機キャラ仮想位置の初期設定
lngSX = 2
lngSY = 2
自機の移動
自機の移動処理では、方向ボタンが押下されたときにその方向に壁があるかを判断し、通路(0)のときは移動処理を行っています。

移動処理で行っている現在位置を表す変数への加減算ですが、ワークシート上での位置を管理する変数lngXlngY、迷路データ上での位置を管理する変数lngSXlngSYでは、移動量が違います。迷路データ1コがワークシート上では縦8×横8の大きさになるので、描画位置は8ずつ、迷路データ上では1ずつです。

 ◆Sheet1のPrivate Sub prcMain()より抜粋
'→を押しているとき
If GetAsyncKeyState(39) <> 0 Then
   If varScreen(lngSY, lngSX + 1) = 0 Then
      '自機キャラの消去
      rngCL.Copy _
          Destination:=Range(Cells(lngY, lngX) _
                           , Cells(lngY + 7, lngX + 7))
      lngX = lngX + 8
      lngSX = lngSX + 1
   End If
'←を押しているとき
ElseIf GetAsyncKeyState(37) <> 0 Then
   If varScreen(lngSY, lngSX - 1) = 0 Then
      '自機キャラの消去
      rngCL.Copy _
          Destination:=Range(Cells(lngY, lngX) _
                           , Cells(lngY + 7, lngX + 7))
      lngX = lngX - 8
      lngSX = lngSX - 1
   End If
'↓を押しているとき
ElseIf GetAsyncKeyState(40) <> 0 Then
   If varScreen(lngSY + 1, lngSX) = 0 Then
      '自機キャラの消去
      rngCL.Copy _
          Destination:=Range(Cells(lngY, lngX) _
                           , Cells(lngY + 7, lngX + 7))
      lngY = lngY + 8
      lngSY = lngSY + 1
   End If
'↑を押しているとき
ElseIf GetAsyncKeyState(38) <> 0 Then
   If varScreen(lngSY - 1, lngSX) = 0 Then
      '自機キャラの消去
      rngCL.Copy _
          Destination:=Range(Cells(lngY, lngX) _
                           , Cells(lngY + 7, lngX + 7))
      lngY = lngY - 8
      lngSY = lngSY - 1
   End If
End If
Copyright(C) 1999-2006 結城圭介。 All rights reserved