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 the 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
.
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.
We must specify the point0
and point1
in the world space.
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.
Finally, we can invoke Physics.OverlapCapsule
with the values calculated so far.
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.
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 of them.
The code presented here has some major problems. The calculation of top and bottom makes a few assumptions, primarily that the capsule is vertically oriented -- by adding/subtracting the half-height to the y-component only. It also does not take into account CapsuleCollider's direction property, which could mean the "height" is applied to the local X or Z axis. One more thing: the top/bottom points should not include radius offsets, as these points are meant to be the *centers* of the top and bottom of the capsule.
Thank you for your detailed comment. I will rewrite this article to take the orientation and the direction into account. But the top/bottom points are each center of the spheres. When the radius offsets are not included, Physics.OverlapCapsule returns the colliders outside the CapsuleCollider.
It seems that the radius is computed using the lossyScale, ignoring rotation. source: https://forum.unity.com/threads/how-is-the-world-space-radius-of-a-sphere-collider-capsule-collider-calculated.1183045/
This is the code I'm using and fiddling with rotation and scale of the capsule and its parents it seems coherent with what happens to the gizmo.
Anyway, thank you for this post.
float radius = capsule.radius;
float height = capsule.height;
float3 center = capsule.center;
float3 direction = float3(0,0,0);
direction[capsule.direction] = 1;
float hdist = height / 2 - radius;
float3 hvec = direction * hdist;
float3 floor_offset = float3( 0, 0.1f, 0 );
float3 start = center - hvec + floor_offset;
float3 end = center + hvec;
var ctr = capsule.transform;
start = ctr.TransformPoint( start );
end = ctr.TransformPoint( end );
float3 w_radius = ctr.lossyScale * float3(radius,radius,radius);
w_radius = ( 1 - direction ) * w_radius;
float max_radius = float.MinValue;
for ( int i = 0; i != 3; ++i )
{
max_radius = max( abs( w_radius[i] ), max_radius );
}
radius = max_radius;
int count = Physics.OverlapCapsuleNonAlloc( start, end, radius, colliders, collisionCheckMask );