サンプルプログラム7 (その4)

プログラマーからひとこと

ついにサンプルプログラムを見ていく旅もここで終わりです。
RPGなら光とか青空とか出てくるムービーが始まるころですが、まだ今回もサンプルプログラムがゲームとして完成してはいないので、青空がふいにくもって真のラスボスが出てくる場面と言ったほうがいいでしょうか。
そこはどうだっていいですね。

今回はゲーム用語のいわゆる「当たり判定」から始まります。
思えばゲームっぽい話がたくさん出てくるサンプルプログラムでした。
あなたのプログラムのウデもかなり上がったんじゃないでしょうか。
これが終わったら、自分でカンタンなゲームを作ってみるのもいいかもしれません。

いまのは死亡フラグみたいなセリフでしたが、フラグのことも学んだあなたなら、このていどのフラグはFALSEにできるはずです。


当り判定を付けよう

インテリ
いままでのプログラムリストをゼンブまとめてみると、こうだったよね。

プログラムリストを表示

神崎
変数EMAXを敵の数に使うようになってるんだね。

博士
敵の数をいつ変えたくなってもいいワケじゃな。前にもちらっと話したが、変数にできるトコロは変数にしておくのはダイジな心くばりじゃ。

ワンパク
まだデキてねェところは……ショットが敵に当たったトキ、か。

インテリ
プログラムでショットが敵に当たるというのは、どういうコトかを考えるとわかるんじゃないかな?

神崎
うーん、ショットの場所と、敵の場所が重なったとき……かな?

ワンパク
ショットの場所は変数MXMYだったよな……。敵の場所はEX(I)EY(I)だから……。つまり、こんなカンジか!?
0080#.  IF MX==EX(I) AND MY==EY(I) THEN GOSUB @EOUT
配列変数(I)をツカッてるから、敵をウゴかすFOR~NEXTの中に入れないとイケねェな。

ハカセ CHKCHR()命令

ワシじゃワシじゃ、今回はやたら顔を出すハカセじゃ。
ここでは話のナガレ的に出てこなかったが、当たり判定にベンリなCHKCHR()という命令があるのを知っておったかな?
このサンプルにはカンケイない話じゃが、カンタンにセツメイしておくぞい。
CHKCHR()命令
たとえばA=CHKCHR(0,0)と書くと、そのトキ画面の(0,0)のバショにナニが表示されているか変数に入るのじゃ。
(0,0)というのはLOCATE命令で使うのと同じヨコ方向とタテ方向の数じゃな。
文字コード
A=CHKCHR(0,0)と書いたトキに変数に入るのは、「ASCIIアスキー文字コード」という数字じゃ。ナンのことかワカらんじゃろうが、ココの数字を見てくれい。
もし今回のサンプルのように、ショットの場所(MX,MY)に敵「Е(文字コード006)」がいるかどうかチェックしたければ、IF CHKCHR(MX,MY)==006 THEN~とやればいいワケじゃな。
インテリ
ここまではいい調子じゃないか。敵にショットが当たったコトが分かったら、次は敵がやられるルーチン@EOUTだね。

神崎
このサンプルだと、ショットが当たった敵はすぐに消えるから、敵を空白スペースで上書きすればいいのかな。
0108#. @EOUT
0109#. LOCATE EX(I),EY(I):PRINT” ”
0110#. RETURN

ワンパク
タシカにそうだが……ちょっと待てよ。コレだと、次に敵のターンがきたトタンに、消えた敵もまた出てきちまうぜ!

神崎
そうか、敵を動かすためにいつも書きなおしていたんだっけ。
いちどショットが当たった敵はPRINTしちゃダメってことだなあ。

インテリ
これも、いままでの応用でなんとかなるんじゃないかな?

ワンパク
そうか! フラグを使うんだな!

神崎
敵1匹ずつに割りあたってるフラグっていうと、ED(I)だね。
ED(I)=0右に動くX=31になるまでX+1@RI
ED(I)=1下におりる1回だけY+1@DW
ED(I)=2左に動くX=0になるまでX-1@LF
ED(I)=3下におりる1回だけY+1@DW

インテリ
消えたっていうトクベツなフラグだから、数字には-1をあてはめようか。
ED(I)=-1消えた表示しない@EOUT
110行に追加しておこう。
0108#. @EOUT
0109#. LOCATE EX(I),EY(I):PRINT” ”
0110#. ED(I)=-1
0111#. RETURN

ワンパク
これでフラグは立ったから、次は敵の表示のトキにそのフラグを調べるのが……えーと、ドコがいいんだ?

インテリ
Еを書いて消すなら、FORループの中ならどこでもいいとも言えるけど。でもどうせなら、もう表示しないってくらいがいいだろうね。

神崎
じゃあ、最初の方だね。
0072#. FOR I=0 TO EMAX-1
0073#.  IF ED(I)==-1 THEN @PASS
#####.
0081#.  @PASS
0082#. NEXT
0083#. RETURN
これでED(I)フラグが-1のときは表示もされずに、次の敵まで飛ばされるよ!

ワンパク
ン……? ハハァ、そういうコトか!
こうすると敵が減るほどごっそりスキップする行が多くなるから、自動的にスピードが早くなる……敵をタオせばタオすほど、ゲームがムズカシくなるってワケだな!

博士
ウムウム。どうやらショクンも、プログラムがダイブ身についてきたようじゃな。

ワンパク
負ける気がしねェゼ!

博士
じゃが、せっかくならココで、よりコウリツのいいプログラムにチャレンジしてみんかな?


処理のスキップをおぼえておこう

ワンパク
コウリツときやがったか。プログラムがウゴけばそれでいいんじゃねェの?

博士
ム……ム。そういう考えもたしかにアリじゃが。
ひとつにはプログラムの動作スピードが早くなるテクニックなので、オボエておけばアトアト「重い」プログラムを動かすのに助かる、というコトはあるぞい。

神崎
アクションゲームにある「処理落ち」とか、そういうやつ?

博士
まあそんなトコロじゃな。もうひとつのメリットとしては、プログラムが見やすくなるコトもある、とも言えるのう。

ワンパク
「見やすくなるコトもある」……?

博士
逆に見にくくなるコトも、ときにはあるかも……

神崎
えー……

博士
ま、まァまァ! じゃからこそ、シンプルプログラムのイマのうちにオボエておこうという話じゃよ。なに、たいしてムズカしいコトではないぞい。

インテリ
ハカセが言いたいのは、たぶんこの部分ですね。
0080#.  IF MX==EX(I) AND MY==EY(I) THEN GOSUB @EOUT

博士
さすがはインテリ君じゃな。さよう、ソコは「敵がやられたとハッキリ決まったら、やられルーチンに行って帰ってくる。それ以外は普通に進む」となっておる。

ワンパク
それでフツウじゃねえか?

博士
しかし、こうすればどうじゃ。
0080#.  IF MX!=EX(I) THEN @PASS
0081#.  IF MY!=EY(I) THEN @PASS
0082#.  ’--- シホ゛ウ
0083#.  LOCATE EX(I),EY(I):PRINT” ”
0084#.  ED(I)=-1
0085#.  @PASS
0086#. NEXT

ワンパク
ン? ……ンンン? 83~84行目は、さっき作ったやられたトキのプログラムだよな。
80行目でMX!=EX(I)ってコトは、ショットのヨコ位置と敵のヨコ位置がチガうってコトだろ。トウゼン当たってないから、@PASSに飛ぶよな。

神崎
81行目のMY!=EY(I)もタテ位置になっただけで、同じことだね。
そのどっちでもないって時は、かならずショットが当たっているって言えるから、そのままやられたことになる……

博士
さよう。もともとのMX==EX(I) AND MY==EY(I)という条件式は、ハッキリしとるがそれだけチェックに時間がかかるものじゃ。
新しいプログラムじゃと、カンタンな理由さえあればザクザク切っているのがワカるじゃろう。

インテリ
やってるコトも、GOTOで飛ぶだけだしね。
それに、まだ敵のやられチェックをカンタンにする方法は残っているよ。

ワンパク
ツマリ今は「敵がゼッタイにやられてない」条件をサガせばいいってコトか? ……やられてない……やられるのはショットが当たったトキ……よし! ゼンゼンわからねえ!

神崎
なにが「よし」なのか分からないけど、たぶん「ショットが画面に出ていない間は、敵はやられない」と言えるんじゃないかな。

インテリ
ソコだね! ショットは変数MSTで表示フラグをカンリしていたから……あとはカンタンだよね。
0080#.  IF MST==FALSE THEN @PASS

ワンパク
ナルホドな。ハナシをききながらだと、ワカりやすいぜ。……ギャクに言えば、コレいきなり見たら、どういうイミなのかワカりづらくねェか?
スナオにIF MX==EX(I) AND MY==EY(I)って書いてあった方がカンタンじゃねえの?

博士
ぜんぶヒテイされてもうたが……そのキモチも、ワカらんでもないわい。スピードを気にせんでいい初心者のコロなら、ムリしてまでやるコトではないのはタシカじゃ。

インテリ
でも、人のプログラムリストを見るときに「どうしてこんな書き方を?」ってギモンはなくなるんじゃないかな。こういうプログラムの書き方があると知っておくのはムダじゃないよ。

博士
ナイスフォローじゃ、インテリ君!
プログラムの書き方にはヒトそれぞれイロイロなポリシーがあるものじゃが、そういう考えカタを知っておくのもひとつのベンキョウじゃぞ。

ワンパク
ベンキョウってヒビキは気にくわねェが……ツギからこういうスキップのしかたを見てもナットクできるのはタシカか。


当たり処理の仕上げをしよう

神崎
あれ? このプログラムRUNしてみると、ときどきショット1発で何匹も倒せることがあるよ。

ワンパク
ホントだな。こりゃアレだぜ、パワーアップとかによくある「カンツウダン」の動きになってるな!

インテリ
「貫通弾」だね。シューティングゲームだと、敵に当たったらそこでショットは消える方がオーソドックスかな? このゲームならそうしないとカンタンすぎるしね。

神崎
ええと、敵に当たったらすぐにショットを消すわけだ。
さっきもやったけどショットの表示フラグは変数MSTだったね。
0083#.  ’--- シホ゛ウ
0084#.  LOCATE EX(I),EY(I):PRINT” ”
0085#.  ED(I)=-1
0086#.  MST=FALSE

ワンパク
MST=FALSEの1行ふやしただけか。イガイにアッサリいくんだな。

インテリ
フラグはうまく使うと、いろいろラクになるものさ。

神崎
あとは、敵を倒したらスコアも上げないとね。

ワンパク
コレはそうムズカしくなさそうな気がするぜ。
とりあえず、サイショに画面の上の方に出しておくんだろ?
0026#. LOCATE 0,0
0027#. PRINT”SCORE: ”;SC
変数SCをスコアってことにしておいたぜ。

神崎
そして、敵がやられた時に10点プラスすれば完成かな。
0085#.  ’--- シホ゛ウ
0086#.  SC=SC+10
0087#.  LOCATE 7,0:PRINT SC

博士
うむ、それで合っておる。合っておるのじゃが……。

ワンパク
ナンだ? RUNしても、ナニもモンダイはなさそうだぜ?

博士
しかし、ワシとしてはこういうプログラムをテイアンしたい!
0085#.  ’--- シホ゛ウ
0086#.  SV=SV+10
#####.
0110#. @SCORE
0111#. IF SV==0 THEN RETURN
0112#. SC=SC+10
0113#. SV=SV-10
0114#. LOCATE 7,0:PRINT SC
0115#. RETURN
メインループから@SCOREGOSUBすると考えてくれい。

ワンパク
どういうこった? 敵がやられたトキは、ただ変数SVに10点プラスして終わりかよ?

神崎
そのあとで、変数SCを変えてPRINTするのはサブルーチン@SCOREでやるんだね。そこで変数SVー10して、またゼロに戻る……

ワンパク
イミがワカらねェな! プログラムが長くなっただけじゃねえか!

インテリ
先に言っちゃうと、これはLOADしたサンプルプログラムだとこうなってるんですよね。

博士
さよう。なぜワシがこんな一見ムダに見えるプログラムにしたのか、ソコがワカるかの?

ワンパク
ムググ……サイゴになってイガイなナゾトキだぜ……。どう見てもムダにしか見えねェが……。

博士
いやジッサイ、このプログラムのままじゃと、ホントにムダなのじゃ。

ワンパク
バカにしてんのか!

博士
このサンプルプログラムはユーザーのショクンの手でカンセイさせるためのモノじゃからのう。そこでイミが出てくるように作ってあるのじゃよ。

神崎
うーん。そうは言っても、どういう時にヤクに立つのか……

インテリ
こういう何のためにあるのか分からないプログラムは、関係のありそうな数をデタラメでも変えてみると、あんがい目に見えて分かるコトもあるよ。

ワンパク
というと、たとえば敵がやられたトキのSV=SV+10SV=SV+1に変えてみる、とかいうコトか?
ヤミクモにRUNしてやろうじゃねェか!

インテリ
画面の前のみんなもジッサイに変えてためしてみよう!

画面
ワンパク
ウ、ウォオ!? 敵を1回撃ったら、スコアが上がりツヅケて止まらねー!

神崎
そうか……考えてみればこうなるのはトウゼンではあるよね。

ワンパク
アァ? ブツブツ……SVが1になってそのアト10引いてまたモドッて0じゃねェからまた10……フムフム。そりゃスコアがいつまでも上がりっぱなしにもなるな!

インテリ
みんなもプログラムの流れを読むと、何が起きたのかだいたいわかるよね!

博士
わざとデタラメにやっておるのじゃから、おかしな動きになるのはトウゼンじゃな。
しかし、このスコアを見てナニかに気付いたのではないかの?

ワンパク
いや、ベツに……

博士
ココまでのナガレがダイナシになるのう……

神崎
あっ! スコアが10点ずつアニメーションで増えるように見えるよ!

ワンパク
そりゃタシカにそう見えるけどよォ……。メインループを1回通るたびに10点増やしてんだからトウゼンじゃ……ハッ!?

インテリ
いいトコロに気付いたね。ギャクに言えば、メインループを1回通るたびに点を増やすようにすると、アニメーションで点数が増えて見えるワケだ。

ワンパク
ナゾがとけてきたゼ……こうすりゃハッキリするな。さっきSV=SV+1にしたトコロをSV=SV+100にしてRUNだ!

画面
博士
うむ! 止まった画面ではよくワカらんが、ミゴトに1匹倒すごとに100点が入り、それが10点ずつアニメーションしておる。

ワンパク
サブルーチン@SCOREを通るたびに、変数SVがカラになるまで10点ずつ増えてるからな! コレはメインループの中でナンドも通ることにイミがあったってワケだ!

博士
モトモトは、たとえば1匹だけ高得点の敵を作ったらボーナス感が出るように、と作ったブブンだったんじゃが、コレももちろんセイカイじゃぞい。

ワンパク
まさかサイゴにこんなクイズがノコッてたとはな……。

インテリ
プログラムをヒトに渡す時は分かりにくい処理にはコメントを付けておくのがキホンだけど、初心者向けのカダイとしては、まあ良かったんじゃないかな。

博士
ケッキョクそういうアツカイなのかのう……?

今回のまとめ

当たり判定
いちばんオーソドックスな当たり判定は、ぶつけるモノの位置とぶつかられるモノの位置を比べることです。ヨコ座標とタテ座標が一致すれば、それは当たっているということになります。
CHKCHR()命令
(変数)=CHKCHR(横座標縦座標
画面の指定した座標に、何のキャラクターが表示されているかが、ASCII文字コードで変数に入ります。