Exemplo n.º 1
0
    /// Sense ground slightly above or at feet level and return true iff ground is detected,
    /// along with out distance to it, positive upward.
    /// Out distance should be positive or zero, zero if just touching ground and positive if slightly above.
    /// If ground is too high or below feet, no ground is detected, return false with outDistance 0 (unused).
    private bool SenseGround(out GroundInfo outGroundInfo)
    {
        outGroundInfo = new GroundInfo();

        Vector2 origin = (Vector2)groundSensorXTr.position + groundDetectionStartMargin * Vector2.up;
        // make sure to compute sum of start and stop margin, not difference,
        // as the former is upward, the latter backward
        int hitCount = Physics2DUtil.RaycastDebug(origin, Vector2.down, groundFilter, RaycastHits,
                                                  groundDetectionStartMargin + groundDetectionStopMargin);

        if (hitCount > 0)
        {
            // only consider first hit
            RaycastHit2D hit         = RaycastHits[0];
            float        hitDistance = hit.distance;
            outGroundInfo.groundDistance = groundDetectionStartMargin - hitDistance;

            if (outGroundInfo.groundDistance < -groundDetectionToleranceHalfRange)
            {
                // we are above ground by a meaningful distance, consider character airborne
                // in the air, we don't use tangent dir so just default to horizontal
                outGroundInfo.groundCollider = null;
                outGroundInfo.tangentDir     = Vector2.right;
                return(false);
            }
            else
            {
                // in all cases we'll update the current ground and tangent direction
                outGroundInfo.groundCollider = hit.collider;

                Vector2 normal = hit.normal;
                outGroundInfo.tangentDir = VectorUtil.Rotate90CW(normal);

                if (outGroundInfo.groundDistance <= groundDetectionToleranceHalfRange)
                {
                    // we're close enough to ground (slightly inside or above)
                    // to consider we are grounded and don't need any offset (prevents oscillation around ground Y)
                    outGroundInfo.groundDistance = 0f;
                    return(true);
                }
                else  // outGroundDistance > groundDetectionToleranceHalfRange
                {
                    // we are inside the ground by a meaningful distance, so keep outGroundDistance for Y adjustment
                    return(true);
                }
            }
        }

        // no ground detected at all, too far from ground
        // in the air, we don't use tangent dir so just default to horizontal
        outGroundInfo.groundCollider = null;
        outGroundInfo.tangentDir     = Vector2.right;
        outGroundInfo.groundDistance = 0f;  // just because we need something for out
        return(false);
    }
Exemplo n.º 2
0
    /// Sense ground slightly above or at feet level and return true iff ground is detected,
    /// along with out distance to it, positive upward.
    /// Out distance should be positive or zero, zero if just touching ground and positive if slightly above.
    /// If ground is too high or below feet, no ground is detected, return false with outDistance 0 (unused).
    private bool SenseGround(out GroundInfo outGroundInfo)
    {
        outGroundInfo = new GroundInfo();

        Vector2 origin = (Vector2)groundSensorXTr.position + groundDetectionStartMargin * Vector2.up;
        // make sure to compute sum of start and stop margin, not difference,
        // as the former is upward, the latter backward
        int hitCount = Physics2DUtil.RaycastDebug(origin, Vector2.down, groundFilter, RaycastHits,
                                                  groundDetectionStartMargin + groundDetectionStopMargin);

        if (hitCount > 0)
        {
            // only consider first hit
            RaycastHit2D hit         = RaycastHits[0];
            float        hitDistance = hit.distance;

            // signed ground distance is negative when inside ground, positive when above ground
            outGroundInfo.groundDistance = -groundDetectionStartMargin + hitDistance;

            float maxStepDownDistance = IsAirborne() ? maxStepDownDistanceAirborne : maxStepDownDistanceGrounded;

            if (-maxStepUpDistance <= outGroundInfo.groundDistance && outGroundInfo.groundDistance <= maxStepDownDistance)
            {
                // in all cases we'll update the current ground and tangent direction
                outGroundInfo.groundCollider = hit.collider;

                Vector2 normal = hit.normal;
                outGroundInfo.tangentDir = VectorUtil.Rotate90CW(normal);

                if (Mathf.Abs(outGroundInfo.groundDistance) <= groundDetectionToleranceHalfRange)
                {
                    // we're close enough to ground (slightly inside or above)
                    // to consider we are grounded and don't need any offset (prevents oscillation around ground Y)
                    outGroundInfo.groundDistance = 0f;
                    return(true);
                }
                else  // Abs(outGroundInfo.groundDistance) > groundDetectionToleranceHalfRange
                {
                    // we are inside the ground by a meaningful distance, so keep outGroundDistance for Y adjustment
                    return(true);
                }
            }
            // else, we are either too much inside ground to step up, or too high above ground to step down
            // continue below as we consider character airborne
        }
        // else, no ground detected at all, so consider character airborne
        // continue below

        // in the air, we don't use tangent dir so just default to horizontal
        outGroundInfo.groundCollider = null;
        outGroundInfo.tangentDir     = Vector2.right;
        outGroundInfo.groundDistance = 0f;  // just because we need something for out in case we didn't enter the block
        return(false);
    }