
ブロック崩しゲームはよく見る作品例ですが、ボールがブロックに当たって跳ね返る角度を「180度-(向き)」のように単純な式で終わらせていることが多いと思います。
これだけだとボールがブロックの横(側面)にぶつかったときに上手く跳ね返ってくれません。
そこで今回は、ボールがブロックの横(側面)に当たっときにちゃんと反対方向に跳ね返るプログラムを組んでみます。
この記事を読んでいただくと、ブロック崩しゲームの中でボールがブロックの上下左右どの面に当たってもうまく跳ね返すスクリプトの作り方とその注意点が分かります。
スクリプトの作り方
完成した動き
ひと言でいうと、ボールがブロックの上下面に当たったときと左右面(側面)に当たったときで跳ね返る角度を分けています。
ブロックの上面または下面に当たったときは、当たった面に対して入射角と反射角が同じになるよう(上面に当たったら上方向、下面に当たったら下方向)に跳ね返して、ブロックの右面または左面に当たったときは、当たった面に対して入射角と反射角が同じになるよう(右面に当たったら右方向、左面に当たったら左方向)に跳ね返しています。
下の画像が完成したアニメーションですがどうでしょうか?
ボールがブロックの側面に当たったときにも跳ね返っているのが分かると思います。

完成したスクリプト
完成したスクリプトの全体です。スプライトはパドルとボールとブロックの3つです。
【パドルのスクリプト】

【ボールのスクリプト】


【ブロックのスクリプト】
- 変数:すべてのスプライト用 or このスプライトのみ
- クローンX座標:このスプライトのみ
- クローンY座標:このスプライトのみ


スクリプトの説明
ここでは、ボールがブロックにぶつかったときの跳ね返し方のプログラムに絞って説明します。
ボールがパドルにぶつかったときの跳ね返し方については、こちらの記事に詳しく書いていますのでここでは省略します。↓↓↓
ポイント①:どの面にボールが当たったかの判断をブロック側にまかせる
【ボールのスクリプト】
ボールがブロックに触れたら、その後の処理をブロック側にまかせてしまいます。
あとで、どの面にボールが当たったのかの結果だけ受け取ります。

ポイント②:ボールがブロックのどの面に触れたかを判別する
この部分が最重要ポイントです。
クローンごとのX座標・Y座標を変数に持たせる
【ブロックのスクリプト】
クローンを作る前に、クローンのX座標とY座標を変数に入れておきます。
これをやってからクローンをつくるようにします。

この時に使う変数「クローンX座標」と「クローンY座標」は、必ず「このスプライトのみ」にチェック入れて作ってください。
そうしないと、クローンごとに異なる値を持たせることはできません。

ボールとブロックの距離を計算して当たった面を区別する
【ブロックのスクリプト】
ボールがブロックに触れた瞬間に、ボールの座標とブロックの座標の距離を求めます。
それがある数値より小さい場合は上面か下面に当たったことにして、ある数値より大きい場合は左右のどちらかに当たったことにします。
今回使っているスプライトの大きさは「ボール:12×12」「ブロック:45×15」です。
そうすると、ボールがブロックに触れたときのX座標の距離は28.5、Y座標の距離は13.5になります。
しかし実際は、ボールは10歩ずつ進んでいるのでX座標の最小の距離は18.5、Y座標の最小の距離は3.5の可能性があります。
これを厳密に制御するのは少し難しいので、実際に動かしてみてちょうど良い数値を探してみてください。

今回の作品例では説明を単純にするために、X座標の距離のみ計算していますが、Y座標の距離も計算して両方とも「もし~なら」の条件に入れると、もう少し厳密になります。
距離は絶対値で表します。
$$|(ボールx座標)-(ブロックx座標)|<24$$
この条件にマッチしたら上下どちらかの面に当たったものとし、マッチしなかったら左右の面に当たったものとします。
そして、それぞれメッセージを送って、それをボール側のスクリプトで受け取ります。

ポイント③:ブロックの当たった面に応じてボールの向きを変える
【ボールのスクリプト】
どの面にボールが当たったかをブロック側で判断してもらったら、その結果をボール側に教えてもらいます。
ここではメッセージを「上下面に当たった」か「左右面に当たった」かのどちらかで受け取っています。
受け取ったら、それぞれで角度を計算してその方向に向きを変えます。
上下面に当たった場合は「180度-(向き)」として、左右面(側面)に当たった場合は「-1×(向き)」とします。

これらのポイントを押さえてスクリプトブロックを作れば、ブロックの上下左右どの面でもボールを跳ね返す動きは完成です!
失敗しやすいポイント
失敗パターン①:変数のつくり方を間違える
今回の重要なポイントの1つとして、クローンされたブロックごとの座標をつかう、ということがあります。
これを実現するには、クローンの座標を入れる変数はプライベート変数(=ローカル変数)として作成しないといけません。
プライベート変数を作るには、「このスプライトのみ」にチェックを入れて作成すればOKです。
一方で「すべてのスプライト用」にチェックを入れるとグローバル変数になります。

失敗パターン②:ボールとブロックの距離設定を厳密にしてしまう
今回の作品例でいうと、半径12のボールと45×15のブロックを使っているので、ボールがブロックの側面に触れたときのX座標の距離は厳密には28.5となります。

これを「もし~なら」の条件に設定してしまうと、ブロックの側面で上手く跳ね返ってくれません。
これはボールが常に10歩ずつ動いているため、一瞬ブロックにめり込む場合があることを考慮していないためです。

応用編
少し発展させて、並べるブロックの中に壊れないブロックをランダムに発生させてみました。
ちゃんとグレーのブロックにぶつかったときは、ブロックは壊れずに跳ね返されてますね。
こんな感じにすると本物のブロック崩しゲームっぽくなってきたのではないでしょうか?
微妙におかしな動きをする場合がありますが、基本の動きは押さえられたので、あとは微調整すればもっときれいな動きにできると思います。
※スペースキーを押すとボールが動き出します。パドルはマウスカーソルに追随して動きます(ただし左右のみ)。

まとめ
さいごに、ブロック崩しゲームの中でボールがブロックの上下左右どの面に当たってもうまく跳ね返すスクリプトの作り方のポイントをまとめます。
- ポイント①:どの面にボールが当たったかの判断をブロック側にまかせる
- ポイント②:ボールがブロックのどの面に触れたかを判別する
- ポイント③:ブロックの当たった面に応じてボールの向きを変える
どうでしたか?上手くできたでしょうか?
他にも役に立つTips(ティップス)記事をたくさん書いてますので、ぜひ見てみてください。(記事のタイトルに「Tips」と書いていたり「Tips」タグを貼ってあります)