2018年5月1日

Unity 指定した座標がコライダー内部にあるか判定する


ある座標がコライダーの内側にあるかどうか確かめる方法をメモメモ…



※このページの内容の動作確認にはUnity5.6を使用しています。
ある点(座標)がコライダーの中に入っているかどうかをスクリプトから確認する方法がないか調べたところ、役に立ちそうなメソッドが2つほど見つかったのでとりあえずメモ。もしかしたらもっと簡単な方法があるかも…

Physics.OverlapSphere

まずは Physics.OverlapSphere を使用する方法です。OverlapSphereは「引数で指定した球形の範囲に接触しているコライダーをすべて取得する」メソッドです。たとえば Physics.OverlapSphere(Vector3.zero, 5f) とすれば、座標(0,0,0)を中心とした半径5の球の中に存在するコライダーをすべて取得できます。今回判定したいのは「点(座標)」なので、半径を0にすればいいですね。

if(Physics.OverlapSphere(point, 0).Any(col => col == collider))
{
 // コライダーの中にある
}
else
{
 // コライダーの外にある
}

というわけでこんなかんじで書いてみました。pointには調べたい座標(Vector3)、 colliderには対象のコライダー(Collider)が入っているとします。

まずOverlapSphereメソッドを使ってpointを中心とする半径0の球…つまり「点」の内部にあるコライダーを配列としてすべて取得します。そして、その配列の中に目的のコライダーがあるかどうか調べ、あればtrueを返すというわけです。ここでは.AnyというLINQの機能を使って1行で書いていますが別にforループとかを使って地道に調べてもかまいません。

Physics2DにはOverlapPointというメソッドが用意されているんですが、Physicsのほうには見当たらなかったのでOverlapSphereで代用してみました。


Physics.ClosestPoint / Collider.ClosestPoint

次に Physics.ClosestPoint / Collider.ClosestPoint を使用する方法です。ClosestPointメソッドは「指定した座標に最も近いコライダー内部の点」を返してくれるメソッドです。

指定した座標(青丸)に最も近いコライダー(Sphere)内部の点(赤丸)を返す

もしも座標がコライダー内部にあった場合はその座標がそのまま返ってきます。これを利用すれば判定するのは簡単です。

if(collider.ClosestPoint(point) == point)
{
 // コライダーの中にある
}
else
{
 // コライダーの外にある
}

「コライダーに最も近い点の座標」と「もとの座標」が一致していれば内部にあるとみなす…とまあそのまんまですね。

ちなみにUnityではVector3どうしの == 演算子は二点間の距離が1e-5(0.00001)以下の場合は誤差として扱われ「同じ位置にある」とみなされます。floatを==で等値比較しちゃダメ!なんてことはよく言われますが、Vector3の場合はある程度配慮されているんですね。

Colliderの種類に注意

ただし1つ注意しておくことがあります。公式リファレンスによると、どうやら上記で紹介したメソッドで扱える対象のコライダーは BoxCollider 、 SphereCollider 、 CapsuleCollider 、あるいは convex を指定した MeshCollider だけに限られているようなのです。つまり、凹みのある複雑な形のコライダーなどに対してこの方法は使えないということになります…

で、何か別の方法はないかとググってみたところ「コライダーの外側から座標に向かってRay(Linecast)を発射し、コライダーと交わった点の数で判定する(交点が奇数個なら内部、偶数個なら外部にある)」というなんだか難しそうな方法が見つかりました。どうしてもという場合はこの方法で実装するのが良いんでしょうか…もっと簡単な方法があればいいのにな~…


0 件のコメント:

コメントを投稿