ブロック崩し>ボールの移動処理

ブロック崩しの第二回。今回は、ボールの移動処理です。

現在作成中のブロック崩しでは、ボールもゲーム画面の情報配列上に数値として書き込むので、ボールが移動するという事は、画面情報配列を書き換えるという事を意味します。ボールが移動すると画面上のブロックがどうなるのか、ボールが何かと衝突したらどうなるのか、という点を画面情報配列の状態に対応させながら考えて行きましょう。

ボールと画面情報配列

まず、今回は画面情報配列の数値と画面上の各要素を以下のように対応させます。

 0  タイル
 1  ブロック 
 2  壁
 3  自機
 4  ボール

つまり、ゲームのプログラム中でボールを動かすという事は画面情報配列に「4」を書く事に対応するわけですね。移動に関しては、自機と同様ボールの現在座標を記憶する変数iBx, iByを用意しましょう。また、ボールは反射や慣性といった一定の法則で常に動きつづけているので、ボールの移動方向を表す変数iDBx, iDByも定義しておきます。移動する時には、iBx, iByiDBx, iDByを加えるわけです。

ボールは常に移動しつづけますが、その「方向」は以下のような規則で変化して行きます。

  • 壁や自機、ブロックなどに当たると移動方向を変える。
  • 方向の変化は、x成分iDBxやy成分iDByの反転である。
  • 他の要素(壁、自機、ブロック)が作る水平、垂直な「壁」に当たった時は当たった方向に応じてx、y成分どちらかが反転する。
  • 他の要素の「角」に当たった時は、x、y両成分が反転する。

移動の方向は、変数iDBx,iDByに入れます。

方向変数
iDBx=0 iDBy=1
右斜め上iDBx=1 iDBy=1
iDBx=1 iDBy=0
右斜め下iDBx=1 iDBy=-1
iDBx=0 iDBy=-1
左斜め下iDBx=-1 iDBy=-1
iDBx=-1 iDBy=0
左斜め上iDBx=-1 iDBy=1

ボールを移動するだけなら、毎回メインループで現在座標iBx, iByにこの値を足せば良いのですが、ゲーム中の処理ではブロックや壁、自機との当たり判定をしなければいけません。これは、「移動しようとしている先に」何があるのか、画面情報配列を見て判定し、他の要素があればボールの移動方向を変えたりボールが当たったブロックを消したりする処理です。
この処理では、ボールの座標を元に画面情報配列を調べる事になり、例えばボールが移動しようとしている先にブロック(数値1)があるかを調べる判定は以下のようになります。

  if (map[iBx+iDBx][iBy+iDBy]==1)

 まず、進行方向の「壁」に当たったら「跳ね返る」処理を考えてみましょう。ここで言う「壁」とは、進行方向に水平または垂直どちらか一方にのみ他の要素がある場合です。例えば、壁(2)や自機(3)が立ち塞がっているかを調べるには、

  if (map[iBx+iDBx][iBy]>1 && map[iBx][iBy+iDBy]==0) /* 水平方向の壁 */

  if (map[iBx][iBy+iDBy]>1 && map[iBx+iDBx][iBy]==0) /* 垂直方向の壁 */

 という判定文になります。判定文の後半は、もう一方が壁になっていない事を確認する部分ですね。

 次に「角」の判定は簡単です。進行方向がすでに「壁」になっているか調べているわけですから、進行方向に壁がなく移動先に障害があればそこは必ず「角」になっています(わかりにくければ、図を描いて確認してみましょう)。

  if(map[iBx+iDBx][iBy+iDBy]==1)

 次に、壁や角にぶつかったときの処理ですが、まず進行方向を変えブロックならぶつかった部分を消す(タイルにする)、という流れになります。具体的には、iDBx, iDByの値を変えてボールの進行方向を変更し、画面情報配列を書き変えてブロックを消す処理が必要です。例えば、水平方向にブロックの壁があるか判定し、あった場合にボールの進路を変えてブロックを消す処理は以下のようになるでしょう。

  if (map[iBx+iDBx][iBy]==1) { /* 水平方向のブロック壁判定 */

      map[iBx+iDBx][iBy]=0; /* ブロックを消す */
      iDBx=-iDBx; /* 進行方向変更 */

  }

 今回は、ボールと壁・自機との当たり判定を分けて行いましたので、ボールの移動処理全体は以下のようになります。


	if (map[iBx+iDBx][iBy]==1) { /* 水平方向のブロック壁判定 */

		map[iBx+iDBx][iBy]=0;
		iDBx=-iDBx;

	} else if (map[iBx][iBy+iDBy]==1) { /* 垂直方向のブロック壁判定 */

		map[iBx][iBy+iDBy]=0;
		iDBy=-iDBy;

	} else if (map[iBx+iDBx][iBy+iDBy]==1) { /* ブロックの角判定 */

		map[iBx+iDBx][iBy+iDBy]=0;

		iDBx=-iDBx;
		iDBy=-iDBy;

	}

	if (map[iBx+iDBx][iBy]>1 && map[iBx][iBy+iDBy]==0) { /* 壁・自機の判定 */

		iDBx=-iDBx;

	} else if (map[iBx][iBy+iDBy]>1 && map[iBx+iDBx][iBy]==0) {

		iDBy=-iDBy;

	} else if (map[iBx+iDBx][iBy+iDBy]>1) {

		iDBx=-iDBx;
		iDBy=-iDBy;

	}


	if (map[iBx+iDBx][iBy+iDBy]>2) {

		map[iBx][iBy]=0;
		iBx+=iDBx;
		iBy+=iDBy;

		map[iBx][iBy]=4;

	}

最後のif (map[iBx+iDBx][iBy+iDBy]>2)という判定は、ボールが壁と自機に挟まれた時に自機を消さないための判定です。この判定をしないと、画面端でボールが自機と壁に挟まれた時に自機がボールで消されてしまいます。

プログラム

プログラムソース表示

カーソルキーで自機を左右に移動できます。ボールが跳ね回っていますので、適当に自機を当てて方向を変えてみてください。


プログラミング資料庫 > ゲーム制作研究室