ポケコンBASICによる

アクションゲーム制作講座 〜入門編〜

第2回 当たり判定を行う



 前回はプレイヤーが操作するキャラを動かす方法について考えたのですがキャラを動かすだけでは「ゲーム」とは呼べないのはですね。しかし、画面上に敵キャラや障害物などがあり、それを動かしたり、壊したり、避けたりすればゲームっぽくなります。
 そういうことで、敵キャラに当たった場合の処理(=当たり判定)について考えてみることにします。

 適当な位置、例えばX座標20、Y座標2に敵キャラ"&"を表示してみましょう。

リスト1
10 CLS :X=0:Y=0:WAIT 5
20 LOCATE 20,2:PRINT "&"
30 K$=INKEY$
40 IF K$="8" AND Y>0 THEN Y=Y-1
50 IF K$="2" AND Y<3 THEN Y=Y+1
60 IF K$="4" AND X>0 THEN X=X-1
70 IF K$="6" AND X<39 THEN X=X+1
80 X=X+V:Y=Y+W
90 LOCATE X,Y:PRINT "P"
100 LOCATE X,Y:PRINT " "
110 GOTO 20

 リスト1を実行し試しに敵キャラにぶつけてみたら分かりますが、敵キャラの上を通り過ぎても何も起こりません。さらに、敵キャラの上からプレイヤーが操作するキャラを上書きすることで敵キャラが消えてしまいました。
 敵キャラ人間の目では敵キャラに当たるかどうかというのは分かりますがそれはその"&"を敵キャラとして認識しているからです。つまり、ポケコンでも同じように"&"が敵キャラであると認識させればいいわけです。

 ここで問題となるのはどうやって認識させるのかということです。
 人間の場合はその形によって"&"を認識しているようにポケコンでも画面表示上の情報から認識させるという方法もありますがそれは現時点では難しい行為なので別の方法を考えることにします。実は、画面上の情報から見なくても"&"を表示している座標はあらかじめ決めてあるのでその座標を元に考えればいいのです。つまり、キャラ"P"のX座標、Y座標が敵キャラ"&"のX座標、Y座標と重なった時にそのキャラは衝突したと見なすことができるわけです。

 では、キャラ"P"と敵キャラ"&"に衝突したらBEEP音を鳴らして終了するというプログラムを作ってみましょう。
 まずは、あらかじめ敵キャラ"&"の座標を変数にいれておかなくてはなりません。変数Aに敵キャラのX座標、変数Bに敵キャラのY座標をあらかじめ入れておいた場合は次ののIF文によって敵キャラと衝突しているかどうか(画面上で重なっているかどうか)が判定できますね。

 IF A=X AND B=Y THEN BEEP 1:END

 さて、この判定をどこに置いたらいいでしょうか。
 とりあえず、75行にでもおいて試してみましょう。

リスト2
10 CLS :A=20:B=2:X=0:Y=0:WAIT 5
20 LOCATE A,B:PRINT "&"
30 K$=INKEY$
40 IF K$="8" AND Y>0 THEN Y=Y-1
50 IF K$="2" AND Y<3 THEN Y=Y+1
60 IF K$="4" AND X>0 THEN X=X-1
70 IF K$="6" AND X<39 THEN X=X+1
75 IF A=X AND B=Y THEN BEEP 1:END
80 LOCATE X,Y:PRINT "P"
90 LOCATE X,Y:PRINT " "
100 GOTO 20

 これを実行してみると敵キャラに重なる前に終了してしまいます。敵キャラに触れたらアウトという設定ならばこれでも良いわけですが、重なったらアウトということで作っているのでこれではまずいです。
 「自分の意図した動きになってないけど一応動いているからいいや」というのではこれから先にどんどんプログラムが複雑化したときに対処できなくなってしまうためにここは妥協せず自分の意図したように動くようにしてみましょう。上のレベル(中級レベル)を目指すならば自分の意図通りのものが作れることが最低条件となりますからね。

 それではリスト2は何が間違っているのでしょうか。IF文の条件に間違いがあるようには見えないのでこのIF文を75行に置いたことに根本的な間違いがありそうです。使用している変数はA、B、X、YのみでですがA、Bの値は固定であるためX、Yが変化していることで条件判断の動作が想定しているものと異なったものになっているのであろうということが予想できます。

 実は、"P"のX、Y座標は40〜70行で新しく計算しなおされているからなのです。その新しい座標での表示は80行で行っているためその間である75行に当たり判定を置くと"P"の見た目の座標と計算上の座標とのギャップが生じてしまいそれが誤動作の原因となっています。
 したがって、新しい座標での"P"の表示が終わった80行目以降に置くのが正しいです。

リスト3
10 CLS :A=20:B=2:X=0:Y=0
20 LOCATE A,B:PRINT "&"
30 K$=INKEY$
40 IF K$="8" AND Y>0 THEN Y=Y-1
50 IF K$="2" AND Y<3 THEN Y=Y+1
60 IF K$="4" AND X>0 THEN X=X-1
70 IF K$="6" AND X<39 THEN X=X+1
80 LOCATE X,Y:PRINT "P"
90 LOCATE X,Y:PRINT " "
95 IF A=X AND B=Y THEN BEEP 1:END
100 GOTO 20

 このように当たり判定はどの行においても良いというものではなく、置ける行には制限があるためは注意が必要になります。しかし、それさえ気をつければ後はそれほど難しくありません。今回の内容だと座標を元に当たり判定をしているので自キャラ、敵キャラの座標計算とキャラ表示の両方が終わった後に判定をする必要があるわけです。

 では、今度は敵キャラを動かしてみましょう。
 移動は最も簡単な乱数を使います。上下左右の4方向に敵キャラが動くようにするには4通りの乱数を発生させなくてはなりません。Z=RND 4とすれば変数Zには1、2、3、4の4つのうちのいずれかの数が代入されます。これでZ=1ならば上、Z=2ならば下、Z=3ならば左、Z=4ならば右へ移動させる場合、プレイヤーのキャラである"P"のキャラ移動と全く同じ方法で移動が可能になります。

リスト4
Z=RND 4
IF Z=1 AND B>0 THEN B=B-1
IF Z=2 AND B<3 THEN B=B+1
IF Z=3 AND A>0 THEN A=A-1
IF Z=4 AND A<39 THEN A=A+1
LOCATE A,B:PRINT "&"
LOCATE A,B:PRINT " "

 この敵キャラ"&"の移動部分(移動ルーチン)をどこに置くかということが問題になりますが、とりあえず"P"の移動ルーチンの前に置くことにします。

リスト5
10 CLS :A=20:B=2:X=0:Y=0:WAIT 5
20 Z=RND 4
30 IF Z=1 AND B>0 THEN B=B-1
40 IF Z=2 AND B<3 THEN B=B+1
50 IF Z=3 AND A>0 THEN A=A-1
60 IF Z=4 AND A<39 THEN A=A+1
70 LOCATE A,B:PRINT "&"
80 LOCATE A,B:PRINT " "
90 K$=INKEY$
100 IF K$="8" AND Y>0 THEN Y=Y-1
110 IF K$="2" AND Y<3 THEN Y=Y+1
120 IF K$="4" AND X>0 THEN X=X-1
130 IF K$="6" AND X<39 THEN X=X+1
140 X=X+V:Y=Y+W
150 LOCATE X,Y:PRINT "P"
160 LOCATE X,Y:PRINT " "
170 IF A=X AND B=Y THEN BEEP 1:END
180 GOTO 20

 このリスト5リスト3と自キャラの移動の部分は変わっておらず、敵キャラの移動が挿入されたので全部入力しなおす必要はないですね。リスト4の30行がリスト5の90行へと変わったのでRENUM 90,30とすればよいです。ただし、このRENUMはGOTOのジャンプ先も自動的に修正してくれるために170行のGOTOのジャンプ先は90行になっているので20行に修正し直す必要があります。

 さて、リスト5を実行すると先ほどまであまり無かったキャラのちらつきが非常に目立ってきました。敵キャラの移動ルーチンの挿入場所が悪いからとも考えられますが、自キャラ"P"の移動ルーチンの後に置いた場合でも症状は変わりません。どうやら根本的に何かが間違っているみたいです。
 そういうことで、もう一度キャラ移動について考えてみることにします。

第3回に行く


RETURN/ RETURN *MAIN inserted by FC2 system