2021-09-06更新: 対象のGameObjectのrotationと、CapsuleColliderのdirectionを考慮するように大きく修正した。
上記のようにCapsulColliderと重なった2つのColliderを取得するには、Physics.OverlapCapsule
を使用する。このメソッドは、カプセルの位置と大きさを受け取り、そのカプセルと重なっているすべてのColliderを返す。
Kinematic Rigidbody Trigger Collierを構成して、OnTriggerEnter
メッセージを処理することでもCollidersを取得できるが、このメソッドのほうが簡単だし、便利な応用方法もある。
Physics.OverlapCapsule
の必須の引数のみのシグネチャを以下に示す。
次の図の左側にこれらの引数を示す。point0
とpoint1
はそれぞれどちらかの半球の中心を表す。radius
には半径が入る。CapsuleColliderの仕様は右側に示すように、中心、高さ、半径からなっている。そのため変換が必要である。
以下は、右のCapsuleColliderに対応するpoint0
とpoint1
の計算方法である。 この計算には、CapsuleColliderのdirectionを考慮する必要がある。directionは0, 1, 2のいずれかであり、それぞれX軸、Y軸、Z軸に対応する。
このlocalPoint0
とlocalPoint1
をワールド空間に変換するとpoint0
とpint1
になる。
Physics.OverapCapsule
の半径もワールド空間なので、CapsuleColliderの半径をワールド空間に変換する必要があるが、少し面倒である。GameObjectがdirectionの垂直面で楕円の場合は、半径を長径側に拡大する必要がある。以下はその実装である。TransformVector
の返すベクトルの要素はマイナスになることがあることに注意してほしい。
最後に、これまでに求めた値を使ってPhysics.OverlapCapsule
を呼び出す。
当然のことながら、返ってくるColliderにはCapsuleColliderも含まれることに注意してほしい。避けたければ、あらかじめCapsuleColliderを無効化しておくとよい。
Physics.OverlapCapsule
を用いると、対象のCapsuleCollderよりもサイズを小さくして、触れているだけのColliderを除外するとか、サイズを大きくして接触しそうなColliderを取得するといったことが自在に行える。
ところで、Physics.OverlapCapsule
は呼ぶたびに配列をアロケートして結果を返すので、毎フレーム呼ぶ場合には大量にゴミが出てしまう。その場合には、Physics.OverlapCapsuleNonAlloc
で事前にアロケートした配列で結果を受け取る。使用例を以下に示す。
重なりを5つまで検出する場合は、5要素のColliderの配列をUpdateの外で作っておく。それをPhysics.OverlapCapsuleNonAlloc
に渡して実行すると、_result
に検出したColliderが格納されて、その数が返値として返る。