多角形同士の当たり判定を行うには

◆PROCESSING 逆引きリファレンス

 カテゴリー:ゲーム作成

多角形同士の当たり判定を行うには

【解説】

多くのゲームでは、物と物が衝突したかどうかを判定する処理(当たり判定)は定番ですね。

例えばシューティングゲームでは、敵と弾が衝突したかどうかを判定し、しかるべき処理を行います。

ゲーム専用のフレームワーク(UnityやCocos2d-X)では、専用の当たり判定命令が用意されています。

残念ながらPROCESSINGには、当たり判定を行う便利な標準命令はありません。

矩形同士、円同士の当たり判定については下記のページで解説しました。

では斜めになっている四角形同士(例えばひし形や、回転する四角形同士)や多角形の当たり判定は、どうしたら良いでしょうか?。

回転する四角形(画像URL:illust-AC 様:うーさん、kaeru-yaさん)

1つの方法として、回転する四角形や多角形同士は、図形の構成要素である各辺(線分)同士が交差しているかどうかを判定する事で、当たり判定を行うことが可能です。

以下は回転している四角形同士の例です。頂点ABCDの四角形(あ)と、頂点EFGHの四角形(い)があります。この時、A-B、B-C、C-D、D-Aの各辺(線分)と、E-F、F-G、G-H、H-Eの各辺(線分)が1つでも交差していれば「当たっている」と考えます。

線分同士まずは、手始めに直線と線分の交差から考えます。

ある1点(x、y)を通過する傾きaの直線L(y=ax+b)をグラフで書くと下記のようになります。むか~し数学の時間に習いましたよね(笑)。
直線グラフAこの時、グラフ上にある点P1、P2がグラフの左側(yより大きな側)にあるか、右側(yより小さい側)にあるかを考えます。以下の様な感じですね。

直線グラフB上図のように、P1とP2がy軸を挟んで大小にわかれる場合、P1ーP2を結ぶ線分と直線は交差している事になります。

P1、P2が下図のように同じ側にあれば、P1ーP2を結ぶ線分と直線は交差しません。

直線グラフC2つの点(x1、y1)ー(x2、y2)を通る直線の方程式は以下のようになりますが

直線式
これを変形した以下の式に検査したい点P1、P2の座標を代入して、求まる結果の大小が同じ符号(正負)になるかどうかで(=つまり y軸を挟んで同じ側にあるかどうかで)判定すれば、直線と線分が交差しているかどうかが判ります。

直線式A
ただしansが0になる場合は、直線と点が重なっていると判定すべきです。

またこの式は直線と線分の交差判定になります。実際に行いたいのは線分同士の交差判定です。

よって例えば下図の場合では、CDを結ぶ仮直線LAと線分EFの交差判定を行い、かつEFを結ぶ仮直線LBと線分CDの交差判定を行って、ともに交差していると判定されるとき「当たり」となります。
線分同士B

この方法を使うと四角形にかぎらず、多角形同士の衝突判定を行うことができるようになります。

※上記記事は フリー教材開発コミュニティFTEXT 様、Visual Basic Library 様の記事を参考とさせて頂きました。ありがとうございます。

例えば、傾いた四角形同士の当たり判定を行うには、傾いた四角形の四隅の点座標(ABCD、EFGH)を計算する必要があります。

傾いた四角形の四隅の点座標は、三角関数を使って計算可能です。

回転していない普通の四角形(あ)を考える時、この四角形が中央を基点にθ度だけ回転したのが、回転している四角形(い)です。
回転する四角形2
これは半径 r の円上にある点(P)がθ度だけ回転して作る点Qと同じことだとわかります。
円上の点PQ
この点Pをθ度だけ回転させた位置にある点Qは、三角関数の「加法定理」により、以下の式で求めることが可能です。
加法定理これをPROCESSINGに適合した式に直すと、以下のようになります。
加法定理※上記はKIT数学ナビゲーション 様、双流蒼天歌 様(2019/04 リンク不在)のページを参考とさせて頂きました。ありがとうございます。

【構文】

float  c  =  cos( float  angle  );
float  s  =  sin( float  angle  );

【パラメータ】

c : 得られたコサイン値
s : 得られたサイン値
angle : 角度(ラジアン)

【注意】

ぞれぞれの三角関数に与える角度は「度」ではなく「ラジアン」です。度からラジアンへの変換は、radians()命令で行えます。

またこれらの関数は、時計回りの角度を扱います。私達が普段数学などで使う角度は反時計回りのことが多いと思いますので、注意してください。

反時計回りで計算したい場合は、負の値を与える必要があります。

【関連記事】


サンプルプログラム

非矩形な四角形の衝突判定例:

上記を実行すると白い四角形(ABCD)と青い四角形(EFGH)を描画し、白い四角形の辺CDと、青い四角形の辺EFが重なっているかどうかを判定します。

isCollisionSide() が当たり判定を行っている関数です。CDを仮直線と見立てて辺EFとのクロスを判定する処理(r1)と、EFを仮直線と見立てて辺CDとのクロスを判定する処理(r2)がある事に注目してください。

どの辺同士を判定しているか目立たせるために、isCollisionSide() の中で判定対象の辺を赤く描画していますが、この処理は判定処理とは直接関係がありません。

<出力サンプル>
collSide

 

加法定理で四角形を回転させる例:

上記を実行すると、画面中央に描かれる白い四角形が、時計回りに回転した青い四角形が描かれます。

caclRotate() が加法定理により座標を回転させている処理です。

<出力サンプル>
加法定理による回転

 

回転する四角形同士の衝突判定例:

上記を実行すると、白い四角形と青い四角形が回転しながら移動し、衝突します。
衝突している間、四角形が赤く描かれます。

回転する四角形の辺同士が重なっているかどうかを判定しているのがisCollisionSide()関数です。

回転する四角形の四隅の座標は加法定理により、caclRotate()関数で計算しています。

<出力サンプル>
collisionRoll
下記はサンプルプログラムをP5.jsで書き直したものです。動作イメージを確認できます。

 


PROCESSING逆引きリファレンス一覧 へ戻る

本ページで利用しているアイコン画像は、下記サイト様より拝借しております。各画像の著作権は、それぞれのサイト様および作者にあります。