/// 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); }
/// 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); }