Kazuhiro Fujieda
Posted on September 25, 2020
Updated on 2021-09-06: This article was largely revised to take into account the rotation of the attached game object and the direction of the CapsuleCollider.
You can use Physics.OverlapCapsule
to get the two Colliders overlapped with the CapsulCollider as above. This method takes the position and size of a capsule and returns all Colliders overlapped by the capsule.
You can also get the Colliders by configuring a Kinematic Rigidbody Trigger Collier and handling the OnTriggerEnter
message, but the method is handy and has useful applications.
The following shows the signature without optional arguments of Physics.OverlapCapsule
.
Collider[] OverlapCapsule(Vector3 point0, Vector3 point1, float radius);
The left side of the following figure illustrates these arguments. Each of point0
and point1
has the center of either of the hemispheres. The radius
has the radius. The specs of a CapsuleCollider on the right side have its center, height, and radius. They are quite different, so you need to convert them.
The following shows how to calculate the point0
and point1
for the CapsuleCollider. The calculation must take into account the direction property of the CapsuleCollder, which can be 0, 1, or 2 correspondings to X, Y, or Z-axis, respectively.
var col = GetComponent<CapsuleCollider>();
var direction = new Vector3 {[col.direction] = 1};
var offset = col.height / 2 - col.radius;
var localPoint0 = col.center - direction * offset;
var localPoint1 = col.center + direction * offset;
We must specify the point0
and point1
in the world space.
var point0 = transform.TransformPoint(localPoint0);
var point1 = transform.TransformPoint(localPoint1);
We must translate the radius of the CapsuleCollider to the world space for the radius
of Physics.OverapCapsule. But, it is not simple. If the attached game object is elliptic on the surface perpendicular to the direction, it is necessary to expand the radius of the CapsuleCollider to the long diameter side.
The following shows the implementation of this translation. Please notice that some components of the vector returned by the TransformVector
can be minuses.
var r = transform.TransformVector(col.radius, col.radius, col.radius);
var radius = Enumerable.Range(0, 3).Select(xyz => xyz == col.direction ? 0 : r[xyz])
.Select(Mathf.Abs).Max();
Finally, we can invoke Physics.OverlapCapsule
with the values calculated so far.
var cols = Physics.OverlapCapsule(point0, point1, radius);
Notice that the returned Colliders naturally include the CapsuleCollider. You can disable it in advance if you want to exclude it.
Physics.OverlapCapsule
is so useful that you can give it a slightly smaller size to exclude just touched Colliders from the result. You can also give it a larger size to get almost colliding Colliders.
By the way, Physics.OverlapCapsule
allocates and returns an array to store the results in each invocation, so it causes a lot of allocation when you invoke it on every frame.
In this case, you should use Physics.OverlapCapsuleNonAlloc
. This variant stores the results to an array allocated in advance. The usage is shown below.
class DetectOverlap
{
readonly Collider[] _result = new Collider[5];
void Update()
{
...
var num = Physics.OverlapCapsuleNonAlloc(point0, point1, radius, _result);
}
}
In this usage, Physics.OverlapCapsuleNonAlloc
can detect up to 5 overlapped Colliders. The method takes an array of 5 Colliders allocated outside Update, stores the results in the array, and returns the number.
Posted on September 25, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 15, 2024