前回はボールの移動と反射の処理を作成しました。
今回はブロックを表示して当たり判定を付けましょう!
いよいよ核心に迫ってきましたね。
※今回作成するプログラムは、ページ最後のリンクからダウンロードすることもできます。
…ですが、この下から始まる本文を読みながら、ご自分で入力するとプログラミングの理解が進むと思いますよ~。
ブロックを表示する前に当たり判定をリニューアルします。
前回は仮で、座標による判定で壁としていました。
今回はきちんと当たりとする値を登録していきます。
当たり判定の手法はいろいろとありますが、今回は「仮想当たり判定マップ」を使います。
これは表示物と対になるよう、仮想的にその位置に何があるかを、判定マップに登録していき、
その判定マップに対して、判断を行うというものです。
この手法を使うと、表示物が何であっても内部では種別ごとに判定を変えることができますし、
その機種専用の判定を行うわけではないので、応用が利きます。
ただしメモリを大量に消費するというデメリットが発生します。
下図は仮想当たり判定マップのイメージです。
前回、カラーモードにすると一番左端の1列は使えないと説明しましたので、仮想当たり判定マップの方も何も無いことになっています。
判定マップには二次元配列変数を使います。(なお要素数を増やせば次元を増やすことができます)
DIM 変数名(要素数1,要素数2)
横が要素数1、縦が要素数2で区切られた方眼用紙を思い浮かべてください。
その区切られた1つ1つのマスに値を登録することができるようになります。
マスへのアクセスは0から数えた位置で指定します。
つまり横5個目、縦3個目のマスは、0から数えるので、変数(4,2)となります。
今回横は0~38の39桁、縦は0~23の24行なので、宣言は以下のようにします。
SCは、今後スコアを付けるための変数で、ここで初期化をしてしまいます。
そして壁を描いていたプログラムも修正し、同時に当たりを登録していくようにします。
まずは一気にプログラムを公開します。一旦NEWして最初から入力した方が良いかもしれません。
(ちなみにリストは画像的に切り貼りしたもので、普通に入力していくと1画面内に
収まりませんので、「1画面内に入らない!」と勘違いしないでくださいね)
それではプログラムを解説していきましょう。
1120行、1125行、1150行、1160行のPRINT文がGOSUBという命令に変わっています。
GOSUBとはある一連の処理(これをサブルーチンといいます)を呼び出す(コールといいます)命令です。
呼び出された側から戻るにはRETURNを使います。
GOSUB サブルーチン行番号
RETURN
この2つはセットで使われます。
1120行を見てみましょう。最後にGOSUB 200とありますね?
これは行番号200を呼び出しています。
処理は行番号200に進んで、次の210行目にRETURNとあります。
ここで呼び出した側の次の命令に戻ります。
さて100行にいきなりGOTO 1000とありますが、どうしてこんなことをしているのでしょうか?
プログラムは作成していくと後ろに伸びていきます。
作成途中で必要なサブルーチンを登録していくと、メインプログラムとサブルーチンが交互に組まれていきます。
そうすると似たようなサブルーチンでも、てんでバラバラの場所に置かれてしまい、理解も難しくなります。
ですので今回は、サブルーチンを前半に集めることにより理解がしやすくなるための工夫と捉えてください。
解説を続けます。
200行を見てください。こちらではX、Yの変数に入った位置に四角を表示しています。
変数の値は、プログラム実行中は一意に決まり、他で参照されても同じ値になります。
呼び出し側を見てみるとFOR~NEXTと直接X、Yに値を入れてコールされているので、その値が使われることになります。
210行では、仮想当たり判定マップへ当たり番号を入れています。
呼び出し元を見るとHN=1(1100行)となっていますので、二次元配列であるMP(X,Y)に1を入れることになります。
今回当たりが有る部分を「1」と定義しました。当たりが無い部分は「0」です。
表示する座標と、仮想当たり判定マップの同じ位置へ当たりを登録しているので、表示と当たり判定が同じ座標で
判断することが可能となるわけです。
2000行から2090行も今回の仮想当たり判定マップ方式に修正されています。
前回の講座で「移動方向側の上下左右を確認すれば良い」と解説しました。
その判定が2010行と2040行にあるHT=MP(X,Y)です。
指定位置に壁があれば1が、何も無ければ0が返ってきますので、壁に当たったら反射処理を行うことがこれで可能になります。
以前は座標で判断していたものが、その位置の当たり判定値を見れば良くなったわけです。
この章では、新しい当たり判定方法=仮想当たり判定マップ方式を導入・解説しました。
これによってどんな形でも判断することが可能となったわけです。
次章では、いよいよブロックを配置して「ブロック崩し」のコア部分を作成していきます。
いよいよブロックを登録していきます。
今回のブロックは1つが3×1の大きさで、横8個×縦4個並べます。
白黒だと寂しいので色を付けながら表示していきましょう。
その前に仮想当たり判定マップへ登録するブロックの当たり番号を決めます。
先ほど壁は「1」としました。
ブロックはボールが当たったら消さないといけません。
と同時に「どの位置か?」というのも知る必要があります。
つまりブロック1つ1つに別々の番号を付けて識別できるようにして、その番号から
表示・非表示の場所を特定します。
今回は「10」からカウントしていって、最後が「41」になります。
(8×4=32個、10から通し番号を付けると41までになります)
これらの条件を反映させると、以下の行を追加することになります。
もちろんサブルーチン化することも忘れません。
順を追って解説します。
1200行~1240行でブロックを登録しています。
1200行では、先ほどブロックの当たり番号は10から通し番号を付けるとしたので、HNに10を入れて、
次にBCに登録ブロックのカウントを行う変数を初期化しています。
これはのちのち全てのブロックを壊したら面クリアを判断するために使います。
1210行は4個×8個のブロックを登録するための繰り返し文です。
1220行ではカラーを指定しています。
ブロックの通し番号からカラー1からカラー6までを計算式で算出しています。
計算式の中にあるMODは余りを計算する演算子です。
ですので、最初は(10 MOD 6)で4になり、そこに1を足すので、カラー5になるという具合です。
そしてブロックの数をカウントします。
1230行は横の座標をXに入れてサブルーチンコールをしています。400行の解説はこの後で行います。
1240行は通し番号を1上げて、NEXTでループを閉じています。
最後のカラー7は白に戻してカラーの後始末を行っています。
400-510行の解説をします。
400-410行はブロックの登録です。
GOSUB 200が3回呼ばれているのがわかるでしょうか?
そうです。横に座標をずらしながら、同じHNの番号で、四角を3つ登録しているんです。
逆に500-510行はブロックの抹消です。
ボールが当たったらブロックを消さないといけないので、その処理です。
実際の抹消はGOSUB 300とありますので、300行からがその機能を担っています。
改めて300-310行を解説しますと、指定の位置に空白を表示して、仮想当たり判定マップに「0」を入れて、
当たりが無いということにしています。
さて、ここまでの説明でブロックの登録ができました。
今、仮想当たり判定マップは以下のようになっています。
そして反射の処理である2030行と2060行にGOSUB 600というのが増えています。
ということで、600行からのサブルーチンを見てみましょう。(ここがブロック判定のキモですよ)
600行ではHTの値が10未満だと戻っています。
これはMP(X,Y)に登録されている値を指していて、現在10未満の値は壁だけです。
壁は反射をするだけなのでそのまま戻っています。
610行と620行で何やら計算をしています。
実はこの計算で当たったブロックの位置を特定しているんです。
式を解読してみましょう。
最初に10を引いていますが、これは10番~41番から0番~31番までに一旦変換しています。
そうすると、ブロックは8列×4行で並んでいますので、以下のように考えることができます。
0行目 0番~7番
1行目 8番~15番
2行目 16番~23番
3行目 24番~31番
その後にYへ8で割った整数値を入れてます。各行は8個ずつ並んでいるので、これで何行目かがわかります。
次の620行では各行の何桁目かを算出して、さらに座標に変換しています。
各行の先頭番号は、Y行目×8個でわかります。その値をHTから引くとその行での桁位置(X)がわかります。
ここまでを例をあげて考えてみましょう。
HTが31の場合、
1.まず31-10=21となる。
2.21/8=2なので、(0から数え始めて)2行目である。
3.21-(8*2)=5なので、(0から数え始めて)5桁目である。
上図にある31番のところを見てください。2行目、5桁目ということがわかると思います。
その後に3を掛けているのは横幅が四角3つ分であり、最後に3を足しているのは、左上のブロックのX原点値です。
次のYに5を足しているのは同様に左上ブロックのY原点値です。
これで個々のブロックの左側X・Y座標が算出されたので、この位置に対してブロック抹消処理(500行)を行えば良いことになります。
ブロック1つは3つの四角で表示されているので、どこに当たっても3つ分の四角を消さないといけないわけですが、
同じ当たり判定番号を付けることにより、計算式で座標が算出できるのです。
これがそれぞれのブロックに通し番号を付けた理由です。
もちろん、今回くらいの簡単なブロック形状と配置だと判定方法は他にもあります。
ですがこの方法の良いところは、「プログラムを拡張すると、ブロックを自由に配置でき、形状も自由にできる」ことなんです。
(応用編はいずれ公開するかもしれません)
この章では、ブロックを配置して破壊することまでできるようになりました。
次の章では当たり判定の補足を行います。
前回の講座で出てきた変数Fの解説になります。
さて、すでにみなさんはプログラムを実行してみたことでしょう。
でも何か気づきませんか?
これが、(青のブロックに当たるね)
こうなる。(ギャー!当たりを抜けた!)
そうです。ブロックの当たりがちょっとおかしいのです。
今までは壁や床、そしてそれに囲まれた場所に対して当たり判定を行って、ボールの反射処理を行っていました。
けれども以下の時の判定が抜けているのです。
わかりますでしょうか?
紫の破線側にも緑の破線側にも当たりが無いので、そのまま角に突っ込んでしまうのです。
(突っ込んだ後は左右にブロックがあるので、そこで改めて反射処理と抹消処理が行われます)
今まではこの状況がなかったので気がつかなかった部分です。
これは対応が必要です。
まず、角かどうかは以下のアルゴリズムで判断します。
そして角だったら、
ということで、この2点を踏まえたプログラムを追加します。
2070行で新しい比較演算子が出てきました。 <> という記号です。
これは、Fが0以外、と読みます。
つまり当たりが1つも無かったら THEN 2220 を実行することになります。
2080行では今から移動する先の仮想当たり判定値を取得しています。
で、引き続いて2090行で当たりが有るかチェックしています。
0は何にも無いので、次の行をスキップしています。
2090行で反射処理を行い、いつものブロック消去判定へGOSUB 600でコールしています。
これで角に対してもきちんと反射するようになりました。
(実はこれ、次回のパドルからの反射で必要な処理なんです)
ということで変数Fは、当たったか当たっていないかを判断するためのフラグでした。
ですが、実はまだ変数Fには秘密があります。
左右に当たった場合は1を、上下に当たった場合は2を加算しているんですが、この区別していることがのちのち重要になってきます。
そしてその解説は次回へ続きます!
ブロックの表示と抹消ができたので、かなりブロック崩し感が出てきましたね!
そして、予想していなかった当たりのパターンに対して、対処を行いました。
次回はいよいよ「パドルの操作」です!お楽しみに!
100 IF ふろく<>更新 THEN 100
200 閲覧
今回入力したプログラムをcmtファイルとしてここに置きます。
BLOCK3.cmt
入力してもうまく動かなかった場合にお使いください。
使い方は、ファイルをダウンロードして、パソコンミニPC-8001のシステムが入っている
microSDの /boot/PCM の下にコピーしてください。
システムを起動して F9->MEDIA にて、 BLOCK3.cmt を SET し、BASIC上で
CLOAD “BLOCK3
で、ロードできます。
DIMで宣言された変数は、最初の値として0で埋められます。
ですので、0でわざわざクリアする必要はありません。
今回のプログラムでも最初は全部0であることを期待して作成しています。