【はじめてのプチコン】武器の当たり判定 | りょうのゲーム塾

りょうのゲーム塾

再開、準備中。

チェックポイント
武器の発射ができたら今度は当たり判定です。
今回のゲームは敵キャラや武器キャラがキャラクタ単位で移動し表示されています。
表示に関しては実際には小数部を持つ実数での移動なんですが表示座標が整数なので小数部分が切り捨てられています。
この場合の当たり判定は敵と武器の位置が一致しているかを判断すればいいのです。


■プログラム
0001 ' initialize
0002 GOSUB @SYS_INI
0003 GOSUB @PLY_INI
0004 GOSUB @WPN_INI
0005 GOSUB @UFO_INI
0006 ' game loop
0007 @LOOP
0008 GOSUB @SYS_MAIN
0009 ' task
0010 GOSUB @PLY_TASK
0011 GOSUB @WPN_TASK
0012 GOSUB @UFO_TASK
0013 GOTO @LOOP
0014 '
0015 ' system
0016 '
0017 @SYS_INI
0018 SYS_CNT = 0
0019 RETURN
0020 '
0021 @SYS_MAIN
0022 VSYNC 1
0023 CLS
0024 SYS_CNT = SYS_CNT + 1
0025 SYS_KEY = BUTTON()
0026 RETURN
0027 '
0028 ' UFO task
0029 '
0030 @UFO_INI
0031 UFO_SX = 0.1
0032 UFO_F = 0
0033 UFO_CNT = 60
0034 RETURN
0035 '
0036 @UFO_TASK
0037 ON UFO_F GOTO @UFO_WAIT,@UFO_MVR,@UFO_MVL
0038 STOP
0039 '
0040 @UFO_WAIT
0041 UFO_CNT = UFO_CNT + 1
0042 IF UFO_CNT > 0 THEN RETURN
0043 GOTO @UFO_RSET
0044 ' move right
0045 @UFO_MVR
0046 LOCATE UFO_X, 0
0047 PRINT "A"
0048 UFO_X = UFO_X + UFO_SX
0049 IF UFO_X > 32 GOTO @UFO_LSET
0050 HITX = UFO_X
0051 HITY = 0
0052 GOSUB @WPN_HITC
0053 IF HITF GOTO @UFO_DETH
0054 RETURN
0055 '
0056 @UFO_LSET
0057 UFO_X = 31
0058 UFO_F = 2
0059 RETURN
0060 ' move left
0061 @UFO_MVL
0062 LOCATE UFO_X, 0
0063 PRINT "A"
0064 UFO_X = UFO_X - UFO_SX
0065 IF UFO_X < 0 GOTO @UFO_RSET
0066 HITX = UFO_X
0067 HITY = 0
0068 GOSUB @WPN_HITC
0069 IF HITF GOTO @UFO_DETH
0070 RETURN
0071 '
0072 @UFO_RSET
0073 UFO_X = 0
0074 UFO_F = 1
0075 RETURN
0076 '
0077 @UFO_DETH
0078 UFO_F = 0
0079 UFO_CNT = 60
0080 RETURN
0081 '
0082 ' player task
0083 '
0084 @PLY_INI
0085 PLY_X = 15
0086 PLY_SX = 0.5
0087 PLY_F = 0
0088 RETURN
0089 '
0090 @PLY_TASK
0091 LOCATE PLY_X,21
0092 PRINT "P"
0093 IF SYS_KEY AND 16 THEN GOSUB @WPN_FIRE
0094 ON PLY_F GOTO @PLY_STOP,@PLY_MVR,@PLY_MVL
0095 STOP
0096 ' stop
0097 @PLY_STOP
0098 IF SYS_KEY AND 8 GOTO @PLY1
0099 IF SYS_KEY AND 4 GOTO @PLY2
0100 RETURN
0101 @PLY1
0102 PLY_F = 1
0103 RETURN
0104 @PLY2
0105 PLY_F = 2
0106 RETURN
0107 ' move right
0108 @PLY_MVR
0109 PLY_X = PLY_X + PLY_SX
0110 IF PLY_X > 31 THEN PLY_X = 31
0111 IF SYS_KEY AND 8 THEN RETURN
0112 PLY_F = 0
0113 RETURN
0114 ' move left
0115 @PLY_MVL
0116 PLY_X = PLY_X - PLY_SX
0117 IF PLY_X < 0 THEN PLY_X = 0
0118 IF SYS_KEY AND 4 THEN RETURN
0119 PLY_F = 0
0120 RETURN
0121 '
0122 ' weapon task
0123 '
0124 @WPN_INI
0125 WPN_F = 0
0126 WPN_SY = 0.5
0127 RETURN
0128 '
0129 @WPN_TASK
0130 ON WPN_F GOTO @WPN_WAIT,@WPN_MOVE
0131 STOP
0132 '
0133 @WPN_WAIT
0134 RETURN
0135 '
0136 @WPN_MOVE
0137 LOCATE WPN_X,WPN_Y
0138 PRINT "!"
0139 WPN_Y = WPN_Y + WPN_SY
0140 IF WPN_Y >= 0 THEN RETURN
0141 WPN_F = 0
0142 RETURN
0143 '
0144 @WPN_FIRE
0145 IF WPN_F THEN RETURN
0146 BEEP 10
0147 WPN_F = 1
0148 WPN_X = PLY_X
0149 WPN_Y = 20
0150 RETURN
0151 '
0152 @WPN_HITC
0153 HITF = 0
0154 IF WPN_F == 0 THEN RETURN
0155 IF FLOOR(WPN_X) != FLOOR(HITX) THEN RETURN
0156 IF FLOOR(WPN_Y) != FLOOR(HITY) THEN RETURN
0157 HITF = 1
0158 '
0159 BEEP 13
0160 WPN_F = 0
0161 RETURN
0162 'End of line


では変更部分の説明を行います。

0002 GOSUB @SYS_INI
0003 GOSUB @PLY_INI
0004 GOSUB @WPN_INI
0005 GOSUB @UFO_INI
0006 ' game loop
0007 @LOOP
0008 GOSUB @SYS_MAIN
0009 ' task
0010 GOSUB @PLY_TASK
0011 GOSUB @WPN_TASK
0012 GOSUB @UFO_TASK
0013 GOTO @LOOP


まずメインでの変更はUFOのタスクの実行を最後に実行しています。
これは今回の当たり判定を行ううえで武器とその当たる相手(敵)の実行がこの順番の方が都合が良かったからです。
しかし実行の順番はゲームループのなかのタスクを呼んでいる命令を入れ替えればいいだけです。
サブルーチンでなかったらこの入れ替えは大変なことになっていたかもしれませんね。
ちなみに初期化の部分は入れ替えなくても問題は無かったのですが私の血液型がA型のせいか揃えています。

0017 @SYS_INI
0018 SYS_CNT = 0
0019 RETURN
0020 '
0021 @SYS_MAIN
0022 VSYNC 1
0023 CLS
0024 SYS_CNT = SYS_CNT + 1
0025 SYS_KEY = BUTTON()
0026 RETURN


システム部分は変更はありませんが、前回の内容についての確認のために説明します。
初期化の部分では SYS_CNT を0で初期化してあります。
これは今後このゲーム中で時間の概念を入れる際のストップウォッチのようなものです。
ここでストップウォッチをスタートしたようなものです。
@SYS_MAIN はゲームループ内から呼び出されます。
SYS_CNT が+1されカウントされています。

0030 @UFO_INI
0031 UFO_SX = 0.1
0032 UFO_F = 0
0033 UFO_CNT = 60
0034 RETURN
0035 '
0036 @UFO_TASK
0037 ON UFO_F GOTO @UFO_WAIT,@UFO_MVR,@UFO_MVL
0038 STOP


UFO部分は少々変更が多いので重要な点だけ解説します。
今までUFOはいきなり画面に現れましたが少しだけ時間を空けて(間を取って)現れるように変更しました。
今までUFOは右へ移動しその後左に移動する、これらを繰り返したわけですが画面に出る前に待つという状態も追加されました。
そこでプレイヤと同じようなプログラムへ変更されました。
UFO_CNT はUFOが画面現れるまでの待ち時間を表します。
今回60という値が代入されていますがこれはどういう意味かわかりますか?

0040 @UFO_WAIT
0041 UFO_CNT = UFO_CNT - 1
0042 IF UFO_CNT > 0 THEN RETURN
0043 GOTO @UFO_RSET


実際にUFOが待つタスクです。
UFO_CNT から1ずつ引いて0でなければ今のままですね。
0になると @UFO_RSET へジャンプしますがこれはただ単に今までの画面左上から右上まで移動するタスクへと変更しているだけです。

すると・・・

そうです1秒間待つのです。
ゲームループを60回待つと約1秒になるからです。
今後、この時間の概念は忘れないこと!!

0045 @UFO_MVR
0046 LOCATE UFO_X, 0
0047 PRINT "A"

0048 UFO_X = UFO_X + UFO_SX
0049 IF UFO_X > 32 GOTO @UFO_LSET
0050 HITX = UFO_X
0051 HITY = 0
0052 GOSUB @WPN_HITC
0053 IF HITF GOTO @UFO_DETH

0054 RETURN
0055 '
0056 @UFO_LSET
0057 UFO_X = 31
0058 UFO_F = 2
0059 RETURN
0060 ' move left
0061 @UFO_MVL
0062 LOCATE UFO_X, 0
0063 PRINT "A"

0064 UFO_X = UFO_X - UFO_SX
0065 IF UFO_X < 0 GOTO @UFO_RSET
0066 HITX = UFO_X
0067 HITY = 0
0068 GOSUB @WPN_HITC
0069 IF HITF GOTO @UFO_DETH

0070 RETURN
0071 '
0072 @UFO_RSET
0073 UFO_X = 0
0074 UFO_F = 1
0075 RETURN


UFOの移動部分はかなり変更されているようにみえますがそうでもありません。
UFOの表示が移動してきました。
これは画面に表示せずに待つタスクが追加されたのでここで表示しないと都合が悪くなったからです。
右も左も同様です。
IF 文は判定が逆になりました。
画面端にきたら右移動は左移動へジャンプ、左移動は右移動へジャンプしています。
では追加されたのは?

0066 HITX = UFO_X
0067 HITY = 0
0068 GOSUB @WPN_HITC
0069 IF HITF GOTO @UFO_DETH


これは当たり判定のサブルーチンを呼び出しています。
呼び出す前に今回当たり判定するための位置データを HITX および HITY にコピーしています。
なぜコピーするかはおいおいわかってきますのでここでは気にしないでください。
例えば上のプログラムの場合当たり判定したい対象、今回はUFOなのでUFOのX座標とY座標を代入しています。
@WPN _HITC は武器のヒット(当たり)をチェックするサブルーチンです。
その結果が HITF に代入されて返ってきます。
HITF が0でないときUFOが消滅するプログラムへジャンプします。

0077 @UFO_DETH
0078 UFO_F = 0
0079 UFO_CNT = 60
0080 RETURN


再びUFOを発生させるためフラグを0にしカウントを60にし60フレーム待つタスクへジャンプすることになります。
タスクのジャンプは他のプログラムのように GOTO 文は使いません。
ですのでジャンプという呼び方は不適当です。

今後はタスクが移行すると呼ぶことにします。

0144 @WPN_FIRE
0145 IF WPN_F THEN RETURN
0146 BEEP 10
0147 WPN_F = 1
0148 WPN_X = PLY_X
0149 WPN_Y = 20
0150 RETURN


武器の発射ルーチンはデバッグの際にわかりやすいように発射音を鳴らしました。

0152 @WPN_HITC
0153 HITF = 0
0154 IF WPN_F == 0 THEN RETURN
0155 IF FLOOR(WPN_X) != FLOOR(HITX) THEN RETURN
0156 IF FLOOR(WPN_Y) != FLOOR(HITY) THEN RETURN
0157 HITF = 1
0158 '
0159 BEEP 13
0160 WPN_F = 0
0161 RETURN


最後に当たり判定のルーチンです。
サブルーチンの実行前に HITX および HITY に当たり判定の対象の座標が入っているのでこれと武器の座標を比べます。
最初に HITF に0を代入しているのは当たっていない条件を判断してその場合に終了するため最初は判定はNGの意味で0が代入されています。
0154行目は武器フラグが0のときは発射されていないのでNGで戻ります。
0155行目は武器のX座標と対象のX座標が違う場合NGとなります。
0156行目は同様にY座標の場合です。
ここまで来るとすべての条件がOKだったので当たったと判断しています。
当たったら武器は発射前の待ちタスクへ移行します。

さあ、どうでしょうか?
理解できましたか?

ちなみに座標の判定を行っている部分で FLOOR という関数を使っています。
これは引数(かっこの中に書いた変数の値)の小数部分を切り捨てた値、要するに整数部分を返します。

なぜだかわかりますよね?