DEV Community

Kazuhiro Fujieda
Kazuhiro Fujieda

Posted on • Updated on • Originally published at roundwide.com

[Unity] How to Use Physics.OverlapCapsule

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.

A CapsuleCollider collides with two Colliders

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);
Enter fullscreen mode Exit fullscreen mode

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.

Arguments of Physics.OverlapCupsule and specs of a CapsuleCollider

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;
Enter fullscreen mode Exit fullscreen mode

We must specify the point0 and point1 in the world space.

var point0 = transform.TransformPoint(localPoint0);
var point1 = transform.TransformPoint(localPoint1);
Enter fullscreen mode Exit fullscreen mode

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();
Enter fullscreen mode Exit fullscreen mode

Finally, we can invoke Physics.OverlapCapsule with the values calculated so far.

var cols = Physics.OverlapCapsule(point0, point1, radius);
Enter fullscreen mode Exit fullscreen mode

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (0)