예제 #1
0
    public bool FindLedgeAtPoint(Vector3 start, Vector3 dir, float maxDistance, float deltaHeight, out LedgeInfo ledgeInfo)
    {
        int notPlayerLayer = ~(1 << 8);

        // Horizontal check
        //
        RaycastHit hHit;

        if (!Physics.Raycast(start, dir, out hHit, maxDistance, notPlayerLayer, QueryTriggerInteraction.Ignore))
        {
            goto NoLedge;
        }

        bool isMoving = hHit.collider.CompareTag("MovingPlatform");

        if (hHit.collider.CompareTag("Freeclimb"))
        {
            ledgeInfo = new LedgeInfo(LedgeType.Free, new Vector3(hHit.point.x, start.y, hHit.point.z), -hHit.normal, hHit.collider);
            return(true);
        }

        // Vertical check
        //
        RaycastHit vHit;

        start    = hHit.point + (dir * minDepth);
        start.y += deltaHeight;

        if (!Physics.Raycast(start, Vector3.down, out vHit, deltaHeight, notPlayerLayer, QueryTriggerInteraction.Ignore))
        {
            goto NoLedge;
        }

        Vector3 rightNormal = vHit.normal - Vector3.Scale(vHit.normal, UMath.MakeXYZPositive(-hHit.normal));

        // Check angle is shallow enough sideways (think shimmying up when going sideways)
        //
        float angleRight = Vector3.Angle(Vector3.up, rightNormal);

        if (angleRight > maxRightAngle)
        {
            goto NoLedge;
        }

        // Check angle is shallow enough straight in front (think grabbing bottom of slope)
        //
        Vector3 ledgeRight = Vector3.Cross(Vector3.up, hHit.normal).normalized;

        Vector3 forwardNormal = vHit.normal - Vector3.Scale(vHit.normal, UMath.MakeXYZPositive(ledgeRight));

        float angleForward = Vector3.Angle(Vector3.up, forwardNormal);

        if (angleForward > maxForwardAngle)
        {
            goto NoLedge;
        }

        // Resolve so Lara grabs correct point on a slope
        float offset = minDepth * Mathf.Tan(angleForward * Mathf.Deg2Rad);

        Vector3 ledgePoint = new Vector3(hHit.point.x, vHit.point.y - offset, hHit.point.z);

        // Check nothing blocking vertically
        //
        start = ledgePoint + hHit.normal * 0.1f - Vector3.up * 0.1f;
        if (Physics.Raycast(start, Vector3.up, 0.2f, notPlayerLayer, QueryTriggerInteraction.Ignore))
        {
            goto NoLedge;
        }

        start = ledgePoint + hHit.normal * 0.1f + Vector3.up * 0.1f;
        if (Physics.Raycast(start, Vector3.down, 0.2f, notPlayerLayer, QueryTriggerInteraction.Ignore))
        {
            goto NoLedge;
        }

        // Check minimum depth
        start = ledgePoint + Vector3.up * 0.1f + hHit.normal * 0.1f;
        if (Physics.Raycast(start, -hHit.normal, minDepth + 0.1f, notPlayerLayer, QueryTriggerInteraction.Ignore))
        {
            goto NoLedge;
        }

        ledgeInfo = new LedgeInfo(LedgeType.Normal, ledgePoint, -hHit.normal, vHit.normal, hHit.collider, angleForward, angleRight);
        return(true);

NoLedge:
        ledgeInfo = new LedgeInfo();
        return(false);
    }