ボールキャッチゲームでの当たり判定
上から落ちてくるボールと、それ受け止めるバーの当たり判定をします。ブロック崩しなどにも応用できます。
1.当たり判定がない場合のプログラム
以下は当たり判定のないプログラムです。ボールはバーを素通りしていきます。
float ball_x;float ball_y;float catcher_x;int migi, hirdari;
void setup() { size(600, 400); ball_x = 300; ball_y = 0; catcher_x = 0;}
void draw() { background(255);
ball_y += 2;
if (ball_y > 400) { ball_y = 0; ball_x = 300; }
fill(0, 255, 0); ellipse(ball_x, ball_y, 50, 50);
catcher_x += (migi + hirdari); fill(255, 0, 0); rect(catcher_x, 300, 100, 30);}
void keyPressed() { if (keyCode == RIGHT) { migi = 5; } if (keyCode == LEFT) { hirdari = -5; }}
void keyReleased() { if (keyCode == RIGHT) { migi = 0; } if (keyCode == LEFT) { hirdari = 0; }}
※上記のプログラムは、左右矢印キーでバーを スムーズに 動かせるように工夫していますので、ちょっと見慣れないコードかもしれません。詳しくは「キーで図形をスムーズに動かすための小技」のページを参照してください。
2.ボールとバーの当たり判定の考え方
当たり、つまりモノ同士がぶつかった(触れた、重なった)状態というのを、プログラムでどう書けばよいでしょうか。
Scratchプログラムでは、
などがあり、何かと触れた時の判定が簡単にできますが、Processingではこのような便利な関数はないので、自分でプログラムしなければなりません。
理解を早めるために、ここではまず条件を簡単にしましょう。つまり、まずはボールの中心座標のみを考え、大きさ(幅)は考慮しないとします。また、バーは上辺のみを考えることにします。
すると、ボールをキャッチした(ボールがバーに当たった)というのは、 ボールがバーより下に来た時に、ボール(の中心座標)はバー(の上辺)の幅の範囲内にある 、ということができます。つまり、
- ボールのy座標がバーのy座標よりも下になった時に
- ボールのx座標はバーの左端のx座標よりも大きい かつ バーの右端のx座標よりも小さい
となります。(下図の、青矢印の範囲内)
やってみよう
上記の条件をプログラムしてみましょう。下記のif文の中の日本語のところにプログラムコードを書いてみてください。
if (ボールのy座標がバーのy座標よりも下になった) { if ((ボールのx座標はバーの左端のx座標よりも大きい) && (ボールのx座標はバーの右端のx座標よりも小さい)) { ball_y = 0; //バーに当たったので、ボールを上に戻す ball_x = 300; }
3.当たり判定がある場合のプログラム
これをプログラムで書くと、以下のようになります。
float ball_x;float ball_y;float catcher_x;int migi, hirdari;
void setup() { size(600, 400); ball_x = 300; ball_y = 0; catcher_x = 0;}
void draw() { background(255);
ball_y += 2;
if (ball_y > 400) { ball_y = 0; ball_x = 300; }
//-----当たり判定を追加-------- if (ball_y > 300) { if ((catcher_x < ball_x ) && (ball_x < (catcher_x + 100))) { ball_y = 0; ball_x = 300; } } //----------------------------
fill(0, 255, 0); ellipse(ball_x, ball_y, 50, 50);
catcher_x += (migi + hirdari); fill(255, 0, 0); rect(catcher_x, 300, 100, 30);}
void keyPressed() { if (keyCode == RIGHT) { migi = 5; } if (keyCode == LEFT) { hirdari = -5; }}
void keyReleased() { if (keyCode == RIGHT) { migi = 0; } if (keyCode == LEFT) { hirdari = 0; }}
「ボールがバーより下に来た時」は (ball_y > 300)
、「ボールはバーの幅の範囲内にある」は (ball_x > catcher_x) && (ball_x < (catcher_x + 100))
です。
ここで &&
は (ball_x > catcher_x)
と (ball_x < (catcher_x + 100))
の条件を結び付けています。そしてこのif文 if ((ball_x > catcher_x) && (ball_x < (catcher_x + 100)))
が成り立つためにはこの2つの条件のどちらも満たす必要がある(かつ/AND条件)ことを示しています。
なお、上記の例ではball_yに関する条件とball_xに関する条件でそれぞれ別のif文にしましたが、これらを全て &&
で結合して1つのif文で書いても構いません。
やってみよう
上記のプログラムは 不完全 です。このプログラムでは、ボールの端がバーの端に当たっていても、当たりとは判定されずに通り過ぎてしまいます。これはボールの中心座標だけ考えていて、ボールの大きさ(幅)を考慮しなかったからです。
また、ボールが通り過ぎた直後にバーがボールの上に行くと、当たりと判定されてしまいます。これはバー(の上辺)よりも下に来た時だけを考えていて、バーの厚さを考慮しなかったからです。
課題集の「ボールキャッチゲームを作ってください」で、この不具合を修正したプログラムを作ってみてください。
(図左)当たりとは判定されない例
(図右)当たりと判定されてしまう例