HSP3 ゲームのプログラミング
 迷路・ゲーム制作 目次へ 次へ 

 迷路はゲームのマップ(地図)など、利用範囲は広い。ここでは、迷路の作成と探索方法を学習して、最終的にはプレイヤーがキャラクタをゴールまで移動させるゲームを制作していく。


(1) 迷路作成(「棒倒し法」)

 迷路を作成するアルゴリズムはいろいろとある。「棒倒し法」、「穴掘り法(道のばし法)」、「壁のばし法」などがある。(これらのキーワードで検索して調べてみよう。)
 ここでは、「棒倒し法」で作成していくことにする。次に、作成手順を示す。

○ 棒倒し法

 グラフ用紙のマス目に壁を書いていくようなイメージである。

1.外枠(壁)を描画する。
2.基準点(壁)を描画する。
 1マス間隔で壁を配置する。したがって、外枠のサイズは「奇数」で設定する。
3.1列目の基準点から壁をのばす。
 基準点から「棒」を上下左右の一方に倒すように壁を配置する。
4.2列目以降の基準点から壁をのばす。
 2列目以降は「棒」を上下右の一方に倒すように配置する。
 [注]左方向には棒を倒さない。


完成

○ プログラミング

(0,0) (1,0) (2,0) (3,0) (4,0)
(0,1) (1,1) (2,1) (3,1) (4,1)
(0,2) (1,2) (2,2) (3,2) (4,2)
(0,3) (1,3) (2,3) (3,3) (4,3)
 マス目を使って迷路を作成していくので、二次元配列に壁と道のデータを格納することにすると考えやすい。座標は(x, y)と表すので、配列の添え字もそれに対応させて考える。

 座標(配列)を(x, y)と表すと、(x, y)を基準に上下左右の座標は計算によって表すことができる。

 ・(x, y)の上 … (x, y - 1)
 ・(x, y)の下 … (x, y + 1)
 ・(x, y)の左 … (x, - 1 y)
 ・(x, y)の右 … (x + 1, y)
(x - 1, y - 1) (x, y - 1) (x + 1, y - 1)
(x - 1, y) (x, y) (x + 1, y)
(x - 1, y + 1) (x, y + 1) (x + 1, y + 1)


サンプル(maze11.hsp)
 迷路の外枠を描画する。迷路作成のプログラムはサブルーチンとして作成する。
 1マスのサイズは8×8ドットとし、迷路全体のサイズは79×49マスとする。

 ゲームでキャラクタを移動させるとき、描画と消去を繰り返す。このとき、毎回迷路を作成するのは時間のムダであるので、別のウィンドウに迷路を作成しておき、gcopy命令でコピーすることにする。

;maze11.hsp
#define bsize 8    ;ブロックサイズ(正方形)
#define bx 79      ;迷路のサイズ(マス目単位)
#define by 49
#define winx1 bx * bsize    ;ウィンドウサイズ
#define winy1 by * bsize
    dim maze, bx, by    ;迷路データ 0:道、1:壁
    randomize
    buffer 1, winx1, winy1    ;迷路描画用
    gosub *maze_make    ;迷路作成
    screen 0, winx1, winy1    ;メインウィンドウ
    pos 0, 0 : gcopy 1, 0, 0, winx1, winy1    ;迷路画像コピー
    stop
;迷路作成(棒倒し法) -----
*maze_make
    ;迷路初期化
    repeat bx
        xx = cnt
        repeat by
            maze(xx, cnt) = 0
        loop
    loop
    ;外枠作成
    repeat bx    ;上下枠
        maze(cnt, 0) = 1
        maze(cnt, by - 1) = 1
    loop
    repeat by    ;左右枠
        maze(0, cnt) = 1
        maze(bx - 1, cnt) = 1
    loop
    ;迷路描画
    color 0, 0, 255
    repeat bx
        cnt1 = cnt
        repeat by
            if maze(cnt1, cnt) = 1 {
                boxf cnt1 * bsize, cnt * bsize, cnt1 * bsize + bsize, cnt * bsize + bsize
            }
        loop
    loop
    return

実行外枠が青色で描画される。

 迷路のデータは配列mazeに格納している。0が道で、1が壁である。
 メインのウィンドウはID0であるから、迷路はウィンドウID1に描画して利用するときにID0にコピーするような方式にする。
 外枠作成では、配列mazeに壁のデータ(1)を格納しているだけである。迷路描画で配列のデータが1(壁)のときだけ四角形を描画している。

 迷路の大きさを変更する場合は、ブロックサイズと迷路サイズ(最初の3行)の値を変更するだけである。



課題(maze61.hsp)
 基準点(壁)を描画する処理を追加する。

ヒント
・壁を描画する座標はxが2, 4, 6, 8, …, 74, 76, 78、yが2, 4, 6, 8, … , 44, 46, 48である。
    repeat bx / 2       ;bxは79なので79/2=39.5であるが、bxは整数型なので29となる。
        xx = cnt * 2        ;xx = 0, 2, 4, 6, 8, …, 74, 76, 78
        repeat by / 2   ;上記と同じ
            maze(xx, cnt * 2) = 壁データ    ;cnt*2 = 0, 2, 4, 6, 8, … , 44, 46, 48
        loop
    loop
 x, yともに0から壁データを設定することになるが、何回設定しても不都合はない。

(リスト)



サンプル(maze12.hsp)
 1列目の基準点から壁をのばす(棒を倒す)処理を追加する。

;maze12.hsp
<< 省略 >>
    stop
;迷路作成(棒倒し法) -----
*maze_make
    ;迷路初期化
    << 省略 >>
    ;外枠作成
    << 省略 >>
    ;基準点作成
    << 省略 >>
    ;基準1列目の壁作成
    xx = 2
    repeat by / 2 - 1, 1
        yy = cnt * 2    ;yy = 2, 4, 6, 8, … , 44, 46, 48
        repeat
            rr = rnd(4)    ;0-3の乱数発生
            if rr = 0 & maze(xx, yy - 1) = 0 {    ;上
                maze(xx, yy - 1) = 1
                break
            }
            if rr = 1 & maze(xx, yy + 1) = 0 {    ;下
                maze(xx, yy + 1) = 1
                break
            }
            if rr = 2 & maze(xx - 1, yy) = 0 {    ;左
                maze(xx - 1, yy) = 1
                break
            }
            if rr = 3 & maze(xx + 1, yy) = 0 {    ;右
                maze(xx + 1, yy) = 1
                break
            }
        loop
    loop
    ;迷路描画
    << 省略 >>
    return

 基準点の座標は、前の課題のようにすれば繰り返しで作ることができる。ただし、1列目だけなのでxxは2で固定である。
 棒を倒す方向は乱数で決定する。方向は上下左右の4方向なので、0〜3の乱数をrnd(4)で発生させ、if文で方向別に壁データを設定している。倒す方向に壁がある場合は方向を決定し直すようにするため、repeat命令で永久ループにしている。したがって、倒す方向に壁データを設定したとき、break命令で永久ループを抜け出す。

実行


課題(maze62.hsp)
 2列目以降の基準点から壁をのばす(棒を倒す)処理を追加する。

ヒント
・サンプルの基準1列目の壁作成を利用して、xが4, 6, 8, …, 74, 76, 78と変わるようにループを追加する。また、左方向には壁を作らない(棒を倒さない)ので、その処理部分は削除する。

(リスト)


 迷路・ゲーム制作 目次へ 次へ 
2007 © Hiroshi Masuda 

 

 

inserted by FC2 system