예제 #1
0
    public override Contact this[int index]
    {
        get
        {
            var contact = Contact.Create(
                startPosition, endPosition);

            contact.shape = null;

            Transform currentTransform = raycastHits[index].collider.transform;

            while (currentTransform != null)
            {
                if (currentTransform == collider.transform)
                {
                    return(contact);
                }

                currentTransform = currentTransform.parent;
            }

            contact.contact         = raycastHits[index];
            contact.contactCollider = raycastHits[index].collider;
            contact.contactPoint    = raycastHits[index].point;
            contact.contactNormal   = raycastHits[index].normal;
            contact.contactDistance = raycastHits[index].distance;

            if (raycastHits[index].distance == 0f)
            {
                var(linePoint, colliderPoint) =
                    ClosestPoint.FromLineSegment(
                        contact.startPosition, contact.endPosition,
                        contact.contactCollider, layerMask);

                if (Missing.IsNaN(colliderPoint))
                {
                    return(contact);
                }

                var delta = colliderPoint - linePoint;

                contact.contactOrigin = linePoint;
                contact.contactPoint  = colliderPoint;

                contact.contactDistance    = math.length(delta) - Radius;
                contact.contactPenetration = (contact.contactDistance < 0f);

                RaycastHit raycastHit;
                if (Raycast.ClosestHit(
                        linePoint, math.normalizesafe(delta), out raycastHit,
                        math.max(contact.contactDistance + Radius, Radius + 0.01f)))
                {
                    contact.contactNormal = raycastHit.normal;
                }
                else if (contact.contactDistance < epsilon)
                {
                    contact.contactNormal =
                        math.normalizesafe(linePoint - colliderPoint);
                }
            }
            else
            {
                contact.contactOrigin = ClosestPoint.FromPosition(
                    contact.contactPoint, contact.startPosition, contact.endPosition);
            }

            contact.contactNormal = math.normalizesafe(contact.contactOrigin - contact.contactPoint);

            contact.shape = this;

            return(contact);
        }
    }
예제 #2
0
    float GetGroundDistance(float3 position)
    {
        var rayStartPosition = position + (math.up() * groundProbeOffset);
        var rayDirection     = -math.up();
        var rayLength        = groundProbeOffset + groundProbeLength;

        bool isGrounded = false;

        RaycastHit raycast;

        var rayCastResult = Raycast.ClosestHit(
            rayStartPosition, rayDirection, out raycast,
            rayLength, layerMask, transform);

        var distance = float.MaxValue;

        if (rayCastResult)
        {
            var tolerance = (groundSnap ? groundSnapDistance : groundTolerance);

            isGrounded           = raycast.distance - groundProbeOffset < tolerance + epsilon;
            distance             = raycast.distance - groundProbeOffset;
            state.current.ground = raycast.collider.transform;
        }

        if (!isGrounded)
        {
            float3 closestPoint = raycast.point;

            rayStartPosition = position + (math.up() * groundSupport);

            Collider[] colliders = null;

            int numContacts = Intersection.OverlapSphere(
                rayStartPosition, groundSupport * oneOverCos45,
                out colliders, layerMask, transform);

            bool ignore = false;

            if (colliders == null || numContacts == 0)
            {
                ignore     = true;
                isGrounded = false;
            }
            else if (numContacts == 1)
            {
                var result = ClosestPoint.FromPosition(
                    position + math.up() * 0.05f, colliders[0]);

                if (!Missing.IsNaN(result))
                {
                    closestPoint = result;

                    var closestPointLocal =
                        state.current.InverseTransformPoint(closestPoint);

                    closestPointLocal.y = 0f;

                    if (closestPointLocal.magnitude < groundSupport)
                    {
                        ignore     = false;
                        isGrounded = true;
                    }
                    else
                    {
                        ignore     = true;
                        isGrounded = false;
                    }
                }
            }
            else
            {
                for (int i = 0; i < numContacts; i++)
                {
                    if (colliders[i] == raycast.collider)
                    {
                        continue;
                    }

                    var candidatePoint = ClosestPoint.FromPosition(
                        position + math.up() * 0.05f, colliders[i]);

                    if (Missing.IsNaN(candidatePoint))
                    {
                        continue;
                    }

                    var candidatePointLocal = state.current.InverseTransformPoint(candidatePoint);

                    if (candidatePointLocal.y >= groundSupport + epsilon)
                    {
                        continue;
                    }

                    candidatePointLocal.y = 0f;

                    if (math.length(candidatePointLocal) < groundSupport)
                    {
                        closestPoint = candidatePoint;

                        isGrounded = true;

                        break;
                    }
                }
            }

            if (!ignore)
            {
                var closestPointLocal = state.current.InverseTransformPoint(closestPoint);

                rayStartPosition = closestPoint + (math.up() * groundSupport);

                rayDirection = -math.up();
                rayLength    = groundSupport + groundTolerance;

                rayCastResult = Raycast.ClosestHit(
                    rayStartPosition, rayDirection, out raycast,
                    rayLength, layerMask, transform);

                if (rayCastResult)
                {
                    distance             = raycast.distance - groundSupport - closestPointLocal.y;
                    isGrounded           = distance < (groundTolerance + epsilon) * oneOverCos45;
                    state.current.ground = raycast.collider.gameObject.transform;
                }
            }
        }

        return(distance);
    }
    public override Contact this[int index]
    {
        get
        {
            var contact = Contact.Create(
                startPosition, float3.zero);

            contact.shape = null;

            Transform currentTransform = raycastHits[index].collider.transform;
            if (currentTransform == collider.transform)
            {
                return(contact);
            }

            while (currentTransform != null)
            {
                if (currentTransform == collider.transform)
                {
                    return(contact);
                }

                currentTransform = currentTransform.parent;
            }

            contact.contact         = raycastHits[index];
            contact.contactOrigin   = contact.startPosition;
            contact.contactCollider = raycastHits[index].collider;
            contact.contactPoint    = raycastHits[index].point;
            contact.contactNormal   = raycastHits[index].normal;

            contact.contactDistance = raycastHits[index].distance;

            if (raycastHits[index].distance == 0f)
            {
                var colliderPoint = ClosestPoint.FromPosition(contact.startPosition, contact.contactCollider, layerMask);

                if (Missing.IsNaN(colliderPoint))
                {
                    return(contact);
                }

                float3 delta = colliderPoint - contact.startPosition;
                if (math.abs(math.length(delta) - Radius) < epsilon)
                {
                    float dot = math.dot(math.normalizesafe(delta), direction);
                    if (dot <= -0.8f)
                    {
                        return(contact);
                    }
                }

                contact.contactOrigin = contact.startPosition;
                contact.contactPoint  = colliderPoint;

                contact.contactDistance    = math.length(delta) - Radius;
                contact.contactPenetration = (contact.contactDistance < 0f);

                RaycastHit raycastHit;
                if (Raycast.ClosestHit(contact.startPosition, math.normalizesafe(delta),
                                       out raycastHit, Mathf.Max(contact.contactDistance + Radius, Radius + 0.01f)))
                {
                    contact.contactNormal = raycastHit.normal;
                }
                else if (contact.contactDistance < epsilon)
                {
                    contact.contactNormal = math.normalizesafe(contact.startPosition - colliderPoint);
                }
            }

            if (!Missing.equalEps(direction, -Missing.up, epsilon))
            {
                RaycastHit raycastHit;
                if (Raycast.ClosestHit(contact.contactPoint - (direction * distance),
                                       direction, out raycastHit, distance + Radius, -1, collider.transform))
                {
                    contact.contactNormal = raycastHit.normal;
                }
            }

            contact.shape = this;

            return(contact);
        }
    }
예제 #4
0
    void InitializeSupport(float3 position)
    {
        var rayStartPosition = position + (math.up() * groundProbeOffset);
        var rayDirection     = -math.up();
        var rayLength        = groundProbeOffset + groundProbeLength;

        RaycastHit raycast;

        bool isGrounded = Raycast.ClosestHit(
            rayStartPosition, rayDirection, out raycast,
            rayLength, layerMask, transform);

        if (isGrounded)
        {
            isGrounded           = (raycast.distance - groundProbeOffset < groundTolerance + epsilon);
            state.current.ground = raycast.collider.gameObject.transform;
            rayLength            = raycast.distance + groundSupport;
        }

        if (!isGrounded)
        {
            float3 closestPoint = raycast.point;

            rayStartPosition = position + (math.up() * groundSupport);

            Collider[] colliders = null;

            var numContacts = Intersection.OverlapSphere(
                rayStartPosition, groundSupport * oneOverCos45,
                out colliders, layerMask, transform);

            bool ignore = false;

            if (colliders == null || numContacts == 0)
            {
                ignore     = true;
                isGrounded = false;
            }
            else if (numContacts == 1)
            {
                var result = ClosestPoint.FromPosition(
                    rayStartPosition, colliders[0]);

                if (!Missing.IsNaN(result))
                {
                    closestPoint = result;

                    var closestPointLocal =
                        state.current.InverseTransformPoint(
                            closestPoint);

                    closestPointLocal.y = 0f;

                    if (closestPointLocal.magnitude > (groundSupport * 0.25f))
                    {
                        ignore     = true;
                        isGrounded = false;
                    }
                }
            }
            else
            {
                for (int i = 0; i < numContacts; i++)
                {
                    if (colliders[i] == raycast.collider)
                    {
                        continue;
                    }

                    var candidatePoint = ClosestPoint.FromPosition(
                        rayStartPosition, colliders[i]);

                    if (Missing.IsNaN(candidatePoint))
                    {
                        continue;
                    }

                    var candidatePointLocal = state.current.InverseTransformPoint(candidatePoint);

                    if (candidatePointLocal.y >= groundSupport + epsilon)
                    {
                        continue;
                    }

                    if (-candidatePointLocal.y > groundTolerance + epsilon)
                    {
                        continue;
                    }

                    candidatePointLocal.y = 0f;

                    if (math.length(candidatePointLocal) < (groundSupport * 0.25f))
                    {
                        closestPoint = candidatePoint;

                        isGrounded = true;

                        break;
                    }
                }
            }

            if (!ignore)
            {
                var closestPointToRayStart = closestPoint - rayStartPosition;

                rayDirection = math.normalizesafe(closestPointToRayStart);
                rayLength    = math.length(closestPointToRayStart) + groundTolerance;

                var rayCastResult = Raycast.ClosestHit(
                    rayStartPosition, rayDirection, out raycast,
                    rayLength, layerMask, transform);

                if (rayCastResult)
                {
                    float groundDistance = raycast.distance - groundSupport;
                    isGrounded           = groundDistance < (groundTolerance + epsilon) * oneOverCos45;
                    state.current.ground = raycast.collider.gameObject.transform;
                }
            }
        }

        state.current.isGrounded = isGrounded;
    }