HSP3 ゲームのプログラミング
 シューティング・ゲーム制作 目次へ 次へ 

 自機をキーボードで移動し、敵機を打ち落とすゲームである。
 プログラムは相当大きくなるので、できるだけ処理ごとにサブルーチンとして作成していく。移動等は8ドット単位の間隔で設定する。

(1) 計画

 次のような画像データを用意する。1つのキャラクタのサイズは基本的に32×32(4×4)ドットである。画像データはプログラムと同じフォルダに保存する。


ダウンロード shoot.bmp (31KB)

○ 画面構成の計画

 画面には、プレイ領域と点数などの表示領域に分ける。 (8ドット単位の座標) = (実際の座標)

(0, 0)=(0, 0)


プレイ領域
(背景色 0, 0, 0)


(50, 60)=(399,479)
(50, 0)=(400, 0)


表示領域
(背景色 0, 30, 50)


(80, 59)=(639, 479)

○ 処理の概略

 処理全体の概要は次の通りである。敵機、自機の移動や当たりの判定を繰り返し実行する。

#define winx 50
#define winy 60
#define mm 8        ;間隔
#define xcls0 color 0, 0, 0 : boxf 0, 0, winx * mm - 1, winy * mm - 1
#define xcls1 color 0, 30, 50 : boxf winx * mm, 0
;初期設定 -----
    ;配列宣言
    ;画像読み込み
    ;メインウィンドウ
;スタート -----
*start
;げーむMain -----
*restart
    ;ゲーム開始前の設定
    repeat
        redraw 0
        xcls0
       ;敵機の処理
       ;自機移動
       ;キー入力
       ;自玉移動
       ;自玉と敵機の当たり判定・敵機消去・得点加算表示
       ;自機と敵機の当たり判定・自機消去・残機減算表示
        redraw 1
        await 80
    loop
    ;ゲームオーバー判定
    end

 実行してもウィンドウが表示されるだけである。

 #define命令は、置き換えの命令である。#define winx 50は、これ以降、winxが現れると50に置き換えてから処理される。この#define命令によって、プレイ領域のサイズを設定している。
 また、同じようにして、プレイ領域と表示領域をそれぞれ消去する命令を #define で定義している。プレイ領域は xcls0 、表示領域は xcls1 で消去できる。

#define winx 50
#define winy 60
#define mm 8     ;間隔
#define xcls0 color 0, 0, 0 : boxf 0, 0, winx * mm - 1, winy * mm - 1
#define xcls1 color 0, 30, 50 : boxf winx * mm, 0



(2) 敵機の移動

サンプル(shoot11.hsp)
 画面の上から下に移動する処理を追加する。下まで移動して消えたら、再度、上から移動する。

 敵機の座標、移動量や状態(有無)を格納する配列を宣言(用意)する。

;初期設定 -----
    ;配列宣言
    teki = 1        ;敵機の数
    dim tkx, teki : dim tky, teki        ;敵機の座標
    dim tkdx ,teki : dim tkdy, teki      ;敵機の移動量
    dim tkb, teki        ;敵機の状態 0=あり、-1=なし
 変数tekiで配列の個数を設定できるようにしている。このようにすることで、1カ所の変更で配列個数の変更が可能になる。

 ゲーム用の画像読み込み、ウィンドウの設定などをする。

    ;画像読み込み
    buffer 1
    picload "shoot.bmp"
    ;メインウィンドウ
    screen 0
    gmode 2, 32, 32
    xcls1
    randomize
 "buffer 1"でウィンドウID 1を初期化して、"picload"でゲームに用意した画像ファイルを読み込む。
 "screen 0"でウィンドウID 0を初期化して、"gmode"で黒色を透明色に、コピーサイズを32×32ドットにするよう、コピーモードを設定する。

 敵機はなしの状態で初期化し、敵機の処理で初期座標などの設定や移動の処理はサブルーチン*teki_jobで行う。

;スタート -----
*start
;げーむMain -----
*restart
    ;ゲーム開始前の設定
    tkb(0) = -1        ;敵機状態、なし
    repeat
        redraw 0
        xcls0
        ;敵機の処理
        gosub *teki_job
        ;自機移動
        ;キー入力
        ;自玉移動
        ;自玉と敵機の当たり判定・敵機消去・得点加算表示
        ;自機と敵機の当たり判定・自機消去・残機減算表示
        redraw 1
        await 80
    loop
    ;ゲームオーバー判定
    end
 "repeat 〜 loop"で敵機などの移動や当たりの判定をする。すなわち、この部分がゲームのメインとなる。ゲームのメインに入る前に、敵機を「なし」の状態に初期設定する。今、敵機が1機なので配列tkb(0)を使っている。
 敵機の処理はサブルーチンとして作成するので、ここでは"gosub"で呼び出すだけである。

 敵機の処理のサブルーチンでは敵機状態がなしであれば、座標や移動量を設定する。また、敵機状態がありであれば、移動の処理をする。

;-------------------------
;----- Subroutine
;敵機の処理 -----
*teki_job
    foreach tkx        ;敵機の数(配列の個数)だけ繰り返す
        ;敵機初期位置・移動量設定
        if tkb(cnt) = -1 & rnd(5) = 0 {
            tkx(cnt) = rnd(winx - 4) + 1    ;x座標
            tky(cnt) = -4    ;y座標
            tkdx(cnt) = 0    ;移動量x
            tkdy(cnt) = 1    ;移動量y
            tkb(cnt) = 0     ;敵機状態あり
        }
        ;敵機移動
        if tkb(cnt) = 0 {        ;敵機がありの時だけ移動処理をする
            pos tkx(cnt) * mm , tky(cnt) * mm
            gcopy 1, 32, 0
            tkx(cnt) = tkx(cnt) + tkdx(cnt)
            tky(cnt) = tky(cnt) + tkdy(cnt)
            ;ウィンドウ外
            if tky(cnt) >= winy : tkb(cnt) = -1    ;敵機状態なしに設定
        }
    loop
    return

 実行すると、敵機が上から下に移動し、敵機が画面の下に消えたら、再度画面の上に現れる。

 "if tkb(cnt) = -1 & rnd(5) = 0"は、本来"if tkb(cnt) = -1"で敵機状態がなしであれば座標などを設定する。しかし、それでは常に敵機が出てくるので、乱数を使って出現の度合いを制限している。"rnd(5) = 0"は0〜4の乱数のうち0のときだけ、という条件で1/5の確率で出現するようにしている。
 y座標の初期値を-4にしているが、0で画面にいきなり出すのではなく少しずつ出てくるようにしている。
 左右に移動しないので、xの移動量は0としている。したがって、移動処理の"tkx(cnt) = tkx(cnt) + tkdx(cnt)"は必要ないが、この後、左右に移動させることも考えて残してある。
 敵機移動は、"if tkb(cnt) = 0"で敵機状態がありの分だけ処理する。敵機の描画は"gcopy 1, 32, 0"で行っている。コピー開始座標を(32, 0)としているが、(64, 0)または(96, 0)で別の敵機でもよい。コピーするサイズはgmodeで設定した32×32ドットである。



課題(shoot61.hsp)
 敵機の数を10機にし、画面の上から下への移動を繰り返す。

ヒント
・配列の個数が敵機の数になる。→teki=1をteki=10に変更する。
・ゲーム開始前の設定で、敵機状態の配列tkbをすべて-1で初期化する。

(リスト)


 シューティング・ゲーム制作 目次へ 次へ 
2007 © Hiroshi Masuda

 

 

inserted by FC2 system