Beispiel #1
0
        public static bool Intersect(SphereXCollider src, SphereXCollider dst, out XContact?contact)
        {
            var dir      = dst.Position - src.Position;
            var sqrDist  = dir.sqrMagnitude;
            var space    = src.Radius + dst.Radius;
            var sqrSpace = space * space;

            if (sqrDist < sqrSpace)
            {
                var dist = Mathf.Sqrt(sqrDist);
                if (dist != 0)
                {
                    contact = new XContact(src, dst, dir.normalized, space - dist);
                }
                else
                {
                    contact = new XContact(src, dst, Vector3.up, src.Radius);
                }
                return(true);
            }
            contact = null;
            return(false);
        }
Beispiel #2
0
        public static bool Intersect(CylinderXCollider src, SphereXCollider dst, out XContact?contact)
        {
            var n = dst.Position - src.Position;

            Vector3 closest = n;
            var     extents = src.bounds.Extents;

            closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x);
            closest.y = Mathf.Clamp(closest.y, -extents.y, extents.y);
            closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z);

            var v = new Vector2(closest.x, closest.z);

            if (v.sqrMagnitude > src.Radius * src.Radius)
            {
                v         = v.normalized * src.Radius;
                closest.x = v.x;
                closest.z = v.y;
            }

            bool inside = false;

            if (n == closest)
            {
                inside = true;
                // 往上下移动的最短距离
                var dist1 = extents.y - Mathf.Abs(closest.y);
                // 往水平四周移动的最短距离
                var dist2 = src.Radius - v.magnitude;

                if (dist1 < dist2)
                {
                    closest.y = closest.y > 0 ? extents.y : -extents.y;
                }
                else
                {
                    v         = v.normalized * src.Radius;
                    closest.x = v.x;
                    closest.z = v.y;
                }
            }

            var dir      = n - closest;
            var sqrDist  = dir.sqrMagnitude;
            var space    = dst.Radius;
            var sqrSpace = space * space;

            if (sqrDist < sqrSpace || inside)
            {
                var dist        = Mathf.Sqrt(sqrDist);
                var normal      = dir.normalized;
                var penetration = space - dist;
                if (inside)
                {
                    normal      = -normal;
                    penetration = space + dist;
                }
                if (normal == Vector3.zero)
                {
                    normal = Vector3.up;
                }
                contact = new XContact(src, dst, normal, penetration);
                return(true);
            }
            contact = null;
            return(false);
        }
Beispiel #3
0
 public static bool Intersect(SphereXCollider src, CylinderXCollider dst, out XContact?contact)
 {
     return(Intersect(dst, src, out contact));
 }
Beispiel #4
0
        public static bool Intersect(CubeXCollider src, SphereXCollider dst, out XContact?contact)
        {
            // 反向旋转sphere的位置,使得可以在cube的坐标系下进行碰撞判断
            var extents = src.Size * 0.5f;
            var invQ    = Quaternion.Inverse(src.Quaternion);
            var invP    = invQ * (dst.Position - src.Position);

            // 以下所有操作都是在cube的坐标系下,随后的实际方向需要进行坐标系转换
            var n       = invP;
            var closest = n;

            closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x);
            closest.y = Mathf.Clamp(closest.y, -extents.y, extents.y);
            closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z);
            var inside = false;

            if (n == closest)
            {
                inside = true;
                var disX = extents.x - Mathf.Abs(n.x);
                var disY = extents.y - Mathf.Abs(n.y);
                var disZ = extents.z - Mathf.Abs(n.z);
                //找到最近的一个面
                if (disX < disY && disX < disZ)
                {
                    // 沿X轴
                    if (n.x > 0)
                    {
                        closest.x = extents.x;
                    }
                    else
                    {
                        closest.x = -extents.x;
                    }
                }
                else if (disY < disX && disY < disZ)
                {
                    // 沿Y轴
                    if (n.y > 0)
                    {
                        closest.y = extents.y;
                    }
                    else
                    {
                        closest.y = -extents.y;
                    }
                }
                else
                {
                    // 沿Z轴
                    if (n.z > 0)
                    {
                        closest.z = extents.z;
                    }
                    else
                    {
                        closest.z = -extents.z;
                    }
                }
            }
            var dir      = n - closest;
            var sqrDist  = dir.sqrMagnitude;
            var space    = dst.Radius;
            var sqrSpace = space * space;

            if (sqrDist < sqrSpace || inside)
            {
                var dist        = Mathf.Sqrt(sqrDist);
                var normal      = (src.Quaternion * dir).normalized;
                var penetration = space - dist;
                if (inside)
                {
                    normal      = -normal;
                    penetration = space + dist;
                }
                if (normal == Vector3.zero)
                {
                    normal = Vector3.up;
                }
                contact = new XContact(src, dst, normal, penetration);
                return(true);
            }
            contact = null;
            return(false);
        }