Example #1
0
        public static bool SphereBox(Vector3 centerOffsetA, float radiusA, Vector3 halfExtentB, out Vector3 push)
        {
            push = Vector3.zero;

            Vector3 closestOnB =
                new Vector3
                (
                    Mathf.Clamp(centerOffsetA.x, -halfExtentB.x, halfExtentB.x),
                    Mathf.Clamp(centerOffsetA.y, -halfExtentB.y, halfExtentB.y),
                    Mathf.Clamp(centerOffsetA.z, -halfExtentB.z, halfExtentB.z)
                );

            Vector3 vec = centerOffsetA - closestOnB;
            float   dd  = vec.sqrMagnitude;

            if (dd > radiusA * radiusA)
            {
                return(false);
            }

            int numInBoxAxes =
                ((centerOffsetA.x <-halfExtentB.x || centerOffsetA.x> halfExtentB.x) ? 0 : 1)
                + ((centerOffsetA.y <-halfExtentB.y || centerOffsetA.y> halfExtentB.y) ? 0 : 1)
                + ((centerOffsetA.z <-halfExtentB.z || centerOffsetA.z> halfExtentB.z) ? 0 : 1);

            switch (numInBoxAxes)
            {
            case 0: // hit corner
            case 1: // hit edge
            case 2: // hit face
            {
                push = VectorUtil.NormalizeSafe(vec, Vector3.right) * (radiusA - Mathf.Sqrt(dd));
            }
            break;

            case 3: // inside
            {
                Vector3 penetration =
                    new Vector3
                    (
                        halfExtentB.x - Mathf.Abs(centerOffsetA.x) + radiusA,
                        halfExtentB.y - Mathf.Abs(centerOffsetA.y) + radiusA,
                        halfExtentB.z - Mathf.Abs(centerOffsetA.z) + radiusA
                    );

                if (penetration.x < penetration.y)
                {
                    if (penetration.x < penetration.z)
                    {
                        push = new Vector3(Mathf.Sign(centerOffsetA.x) * penetration.x, 0.0f, 0.0f);
                    }
                    else
                    {
                        push = new Vector3(0.0f, 0.0f, Mathf.Sign(centerOffsetA.z) * penetration.z);
                    }
                }
                else
                {
                    if (penetration.y < penetration.z)
                    {
                        push = new Vector3(0.0f, Mathf.Sign(centerOffsetA.y) * penetration.y, 0.0f);
                    }
                    else
                    {
                        push = new Vector3(0.0f, 0.0f, Mathf.Sign(centerOffsetA.z) * penetration.z);
                    }
                }
            }
            break;
            }

            return(true);
        }