Example #1
0
    public override bool IsDangling()
    {
        bool hit = Physics.Raycast(m_CapsuleCollider.GetCapsuleTransform().GetDownCenter(), Vector3.down, m_CapsuleCollider.GetRadius() + m_CapsuleCollider.GetGroundedMargin(), m_CapsuleCollider.GetLayerMask());

        if (hit)
        {
            return(false);
        }
        else
        {
            return(true);
        }
    }
Example #2
0
    //This context uses raycasts to determine if a ledge is present.
    //The raycasts originate from above and to the left/right of the character, and are casted downwards
    public void UpdateWithCollisions()
    {
        RaycastHit rightHit;
        RaycastHit leftHit;
        bool       rightHasHit = false;
        bool       leftHasHit  = false;

        m_HasHitEdge = false;
        Vector3 upCenter       = m_CapsuleCollider.GetUpCenter();
        Vector3 upDirection    = m_CapsuleCollider.GetUpDirection();
        Vector3 transformRight = m_CapsuleCollider.transform.right;
        //Orient against wall to the side, even if not able to wallsliding
        //This allows the character to grab onto ledges on slanted walls
        CSideCastInfo sideInfo = m_CapsuleCollider.GetSideCastInfo();

        if (sideInfo.m_HasHitSide)
        {
            Vector3 sideNormal = sideInfo.GetSideNormal();
            Vector3 sidePoint  = sideInfo.GetSidePoint();
            Vector3 sideUp     = CState.GetDirectionAlongNormal(Vector3.up, sideNormal);

            RaycastHit properSideHit;
            if (Physics.Raycast(sidePoint + sideNormal * 0.2f + sideUp * 0.05f, -sideNormal, out properSideHit, 0.3f, m_CapsuleCollider.GetLayerMask()))
            {
                Vector3 newPoint  = properSideHit.point;
                Vector3 newNormal = properSideHit.normal;
                Vector3 newUp     = CState.GetDirectionAlongNormal(Vector3.up, newNormal);

                Vector3          pivot       = upCenter - newPoint;
                Quaternion       rotation    = Quaternion.FromToRotation(upDirection, newUp);
                Vector3          newUpCenter = newPoint + rotation * pivot;
                CapsuleTransform transform   = m_CapsuleCollider.GetCapsuleTransformCopy();
                transform.SetUpDirection(newUp);
                transform.SetUpCenter(newUpCenter);

                upCenter       = newUpCenter;
                upDirection    = newUp;
                transformRight = transform.GetRightDirection();
            }
        }
        //Determine the starting positions of the raycasts
        Vector3 centerStart = upCenter + upDirection * (m_CapsuleCollider.GetRadius() + m_CapsuleCollider.GetEdgeCastVerticalMargin());
        Vector3 sideOffSet  = transformRight * (m_CapsuleCollider.GetRadius() + m_CapsuleCollider.GetEdgeCastHorizontalDistance());
        Vector3 grabLength  = -upDirection * (m_CapsuleCollider.GetEdgeCastVerticalDistance() + m_CapsuleCollider.GetEdgeCastVerticalMargin());

        //The raycasts originate from above and to the left/right of the character, and are casted downwards
        //The angle of the slope they hit can't be too steep, or the character will slide off.
        if (Physics.Raycast(centerStart + sideOffSet, -upDirection, out rightHit, grabLength.magnitude, m_CapsuleCollider.GetLayerMask()))
        {
            if (Vector3.Angle(rightHit.normal, upDirection) < m_CapsuleCollider.GetMaxGrabAngle())
            {
                rightHasHit = true;
            }
        }
        if (Physics.Raycast(centerStart - sideOffSet, -upDirection, out leftHit, grabLength.magnitude, m_CapsuleCollider.GetLayerMask()))
        {
            if (Vector3.Angle(leftHit.normal, upDirection) < m_CapsuleCollider.GetMaxGrabAngle())
            {
                leftHasHit = true;
            }
        }
        if (rightHasHit || leftHasHit)
        {
            RaycastHit castToUse;
            Vector3    wallProbeDirection;
            if (rightHasHit && leftHasHit)
            {
                if (leftHit.distance < rightHit.distance)
                {
                    castToUse          = leftHit;
                    wallProbeDirection = -transformRight;
                }
                else
                {
                    castToUse          = rightHit;
                    wallProbeDirection = transformRight;
                }
            }
            else if (rightHasHit)
            {
                castToUse          = rightHit;
                wallProbeDirection = transformRight;
            }
            else
            {
                castToUse          = leftHit;
                wallProbeDirection = -transformRight;
            }

            //Check if the character can even hold on. The distance between the character and the start of the raycastpoint should not be blocked by a collider (no grabbing on ledges on the other side of walls
            if (Physics.Raycast(centerStart, wallProbeDirection, m_CapsuleCollider.GetRadius() + m_CapsuleCollider.GetEdgeCastHorizontalDistance(), m_CapsuleCollider.GetLayerMask()))
            {
                return;
            }

            wallProbeDirection = CState.GetDirectionAlongNormal(wallProbeDirection, castToUse.normal);
            //After detecting that collider can hang onto edge, orient properly against surface
            RaycastHit probeHit;
            Vector3    probedNormal = CState.GetDirectionAlongNormal(-wallProbeDirection, Vector3.up);
            if (Physics.Raycast(upCenter, wallProbeDirection, out probeHit, m_CapsuleCollider.GetRadius() + m_CapsuleCollider.GetEdgeAlignProbeDistance(), m_CapsuleCollider.GetLayerMask()))
            {
                float angle = Vector3.Angle(probeHit.normal, Vector3.up);
                if (angle < m_CapsuleCollider.GetMaxEdgeAlignAngle())
                {
                    probedNormal = probeHit.normal;
                }
            }
            Vector3 newUpDirection = CState.GetDirectionAlongNormal(Vector3.up, probedNormal);
            Vector3 headPoint      = castToUse.point + probedNormal * (m_CapsuleCollider.GetRadius() + m_CapsuleCollider.GetEdgeCastHorizontalDistance()) - newUpDirection * m_CapsuleCollider.GetRadius();
            //Block check
            //Check if something is obstructing the proposed headposition (and fix if so)
            RaycastHit blockHit;
            if (Physics.Raycast(headPoint, -probedNormal, out blockHit, m_CapsuleCollider.GetRadius(), m_CapsuleCollider.GetLayerMask()))
            {
                if (blockHit.distance < m_CapsuleCollider.GetRadius())
                {
                    Vector3 alongNormal = -CState.GetDirectionAlongNormal(wallProbeDirection, castToUse.normal);
                    castToUse.point += alongNormal * (m_CapsuleCollider.GetRadius() - blockHit.distance) / Vector3.Dot(alongNormal, blockHit.normal);

                    headPoint = castToUse.point + probedNormal * (m_CapsuleCollider.GetRadius() + m_CapsuleCollider.GetEdgeCastHorizontalDistance()) - newUpDirection * m_CapsuleCollider.GetRadius();
                }
            }

            //Rotation check, check if character is aligned to wall or dangling
            //then check if that rotation can be achieved
            CapsuleTransform copy = m_CapsuleCollider.GetCapsuleTransformCopy();
            copy.SetUpCenter(headPoint);
            if (Vector3.Angle(Vector3.up, probedNormal) > m_CapsuleCollider.GetMaxWallAngle() || Vector3.Angle(Vector3.up, probedNormal) < m_CapsuleCollider.GetMaxGroundedAngle())
            {
                return;
            }

            if (copy.CanRotate(newUpDirection, RotateMethod.FromTop))
            {
                m_EdgePoint            = castToUse.point;
                m_EdgeNormal           = castToUse.normal;
                m_EdgeTransform        = castToUse.transform;
                m_WallNormal           = probedNormal;
                m_UpDirection          = newUpDirection;
                m_ProposedHeadPosition = headPoint;
                m_HasHitEdge           = true;
            }
        }
    }
Example #3
0
 //--------------------------------------------------------------------------------------------------------------------------------
 //Can a capsuletransform be manipulated (moved, rotated, resized) without intersecting colliders
 //--------------------------------------------------------------------------------------------------------------------------------
 public bool CanExistHere()
 {
     return(!Physics.CheckCapsule(GetDownCenter(), GetUpCenter(), m_CapsuleCollider.GetRadius() - m_CapsuleCollider.GetRotateCastMargin(), m_CapsuleCollider.GetLayerMask()));
 }
Example #4
0
    //Side cast receives the results of two capsulecasts (to the left and the right of the capsule).
    //It uses this first to determine whether there is a hit to the side of the capsule, and then whether or not this hit could signify a wall.
    //Mostvalidhit stores information on this sidecast. Sidecast information can sometimes be used without wallcast information
    public void UpdateWithCollisions(List <RaycastHit> leftHitResults, List <RaycastHit> rightHitResults)
    {
        m_HasHitSide    = false;
        m_WallCastCount = 0;
        if (leftHitResults.Count == 0 && rightHitResults.Count == 0)
        {
            return;
        }
        List <RaycastHit> resultsToUse = null;

        //First determine which side to use (based on distance)
        if (leftHitResults.Count == 0)
        {
            resultsToUse = rightHitResults;
        }
        else if (rightHitResults.Count == 0)
        {
            resultsToUse = leftHitResults;
        }
        else
        {
            float lowestSideDistance = float.MaxValue;
            for (int i = 0; i < leftHitResults.Count; i++)
            {
                if (leftHitResults[i].point.y < lowestSideDistance)
                {
                    lowestSideDistance = leftHitResults[i].distance;
                    resultsToUse       = leftHitResults;
                }
            }
            for (int i = 0; i < rightHitResults.Count; i++)
            {
                if (rightHitResults[i].point.y < lowestSideDistance)
                {
                    lowestSideDistance = rightHitResults[i].distance;
                    resultsToUse       = rightHitResults;
                }
            }
        }
        m_HasHitSide   = true;
        m_MostValidHit = resultsToUse[0];
        float lowestDistance = float.MaxValue;

        for (int i = 0; i < resultsToUse.Count; i++)
        {
            if (resultsToUse[i].distance < lowestDistance)
            {
                lowestDistance = resultsToUse[i].distance;
                m_MostValidHit = resultsToUse[i];
            }
        }

        //Capsulecasts can give unusable results on corners.
        //Cast a little bit up and down from the initial point to get a better normal.
        RaycastHit correctingCast1, correctingCast2;
        Vector3    dirAlongNormal  = CState.GetDirectionAlongNormal(Vector3.up, m_MostValidHit.normal);
        bool       correctCast1Hit = Physics.Raycast(m_MostValidHit.point + m_MostValidHit.normal * 0.02f + dirAlongNormal * 0.01f, -m_MostValidHit.normal, out correctingCast1, 0.03f, m_CapsuleCollider.GetLayerMask());
        bool       correctCast2Hit = Physics.Raycast(m_MostValidHit.point + m_MostValidHit.normal * 0.02f - dirAlongNormal * 0.01f, -m_MostValidHit.normal, out correctingCast2, 0.03f, m_CapsuleCollider.GetLayerMask());

        if (correctCast1Hit || correctCast2Hit)
        {
            RaycastHit correctCastToUse = m_MostValidHit;
            if (correctCast1Hit && correctCast2Hit)
            {
                float dot1 = Vector3.Dot(m_MostValidHit.normal, correctingCast1.normal);
                float dot2 = Vector3.Dot(m_MostValidHit.normal, correctingCast2.normal);
                if (dot1 < 0.95f && dot2 < 0.95f)
                {
                    if (dot1 > dot2)
                    {
                        correctCastToUse = correctingCast1;
                    }
                    else
                    {
                        correctCastToUse = correctingCast2;
                    }
                }
            }
            else if (correctCast1Hit)
            {
                if (Vector3.Dot(m_MostValidHit.normal, correctingCast1.normal) < 0.95f)
                {
                    correctCastToUse = correctingCast1;
                }
            }
            else
            {
                if (Vector3.Dot(m_MostValidHit.normal, correctingCast2.normal) < 0.95f)
                {
                    correctCastToUse = correctingCast2;
                }
            }
            m_MostValidHit = correctCastToUse;
        }
        m_Distance = lowestDistance - m_CapsuleCollider.GetSideCastMargin();
        WallCast(m_MostValidHit);
    }