0
\$\begingroup\$

I'm using a raycast to detect the player's distance to the ground for a hovercraft game.

The raycast works correctly (returns true and also returns the distance to the first impact) until the moment the craft actually touches the ground. When the player hits the ground, the raycast should theoretically return true and return the distance as near 0f. Instead, it returns false, meaning the raycast isn't colliding with anything over the length of the ray. As a result, it can't find the distance.

I'm having a hard time troubleshooting this, and I wonder if anyone can lend a fresh pair of eyes.

Ray ray = new Ray (transform.position, Vector3.down);
RaycastHit ray_result;
bool hit_ground = Physics.Raycast (ray, out ray_result, optimal_vertical_distance * 2);
if (ray_result.distance < optimal_vertical_distance && vertical_force < max_vertical_force)
  {
  vertical_force += vertical_acceleration;
  }
if ((!hit_ground || ray_result.distance > optimal_vertical_distance) && vertical_force > min_vertical_force)
    {
    vertical_force -= vertical_acceleration;
    }
  }
body.AddForce (Vector3.up * vertical_force, ForceMode.Acceleration);

The only time hit_ground worked correctly was when I increased the thickness of the floor from 2 units to 4 units and set the ray to start from 2 units above the craft instead of from the craft itself. I don't understand why it works, though. However, in that example, ray_result.distance seems to be locked at -1.10999, regardless of how far away the craft is.

\$\endgroup\$
1
\$\begingroup\$

My collider was in the wrong position.

It appeared that my collider mesh was perfectly lined up with my model. When I zoomed in very close in 2D mode, I was able to see that the bottom of the player's model was extending about .1 units past the bottom edge of the collider. Thus, when the collider would hit the ground, the bottom of the model would be intersecting the ground, and, consequently, the origin point of the raycast would be in the ground as well (since I was setting the origin near the bottom of the model). Since raycast ignores any mesh inside its origin point, it thought the ground was part of the player.

\$\endgroup\$
-1
\$\begingroup\$

You should check all Physics.Raycast overloads on the Documentation. You are using the default one, which checks a ray at a given distance, modifies a RaycastHit, this method returns true if it hits anything, even the origin's object, and since you are casting it from transform.position which will:

  • Always return true.
  • The RaycastHit passed as reference will have the ray origin's transform.

What you could do, is to have a LayerMask attribute on that class (or anywhere, depending your code architecture) and use the Physics.Raycast overload that takes also a LayerMask, that parameter is used to selectively ignore layers, and just consider the layer(s) given. Example:

public class LameExample : MonoBehaviour
    {
        public LayerMask layers;
        public float rayDistance;
        private bool grounded;

        void Update()
        {
            RaycastHit hit;
            Ray ray = new Ray(transform.position, Vector3.down);

            grounded = Physics.Raycast(ray, out hit, rayDistance, layers);
        }
    }

You could also consider cast the ray from the bottom border of your object, plus a padding, to give a more precise raycast length, see Bounds' API for more reference. Example:

public class LameExample : MonoBehaviour
{
    public LayerMask layers;
    public float rayDistance;
    public float padding; // Use a tiny number, like 0.1f
    private bool grounded;
    private Renderer renderer;

    void Awake()
    {
        renderer = GetComponent<Renderer>();
    }

    void Update()
    {
        RaycastHit hit;
        Vector3 boundExtent = new Vector3(0f, -renderer.bounds.extents.y + padding, 0f);
        Ray ray = new Ray(transform.position + boundExtent, Vector3.down);

        grounded = Physics.Raycast(ray, out hit, rayDistance, layers);
    }
}

Hope it helps.

\$\endgroup\$
  • \$\begingroup\$ I like these ideas, but, unfortunately, making these changes causes the raycast to report false all the time. \$\endgroup\$ – Nightmare Games Mar 19 '18 at 5:16
  • 1
    \$\begingroup\$ This section: "since you are casting it from transform.position which will: Always return true. The RaycastHit passed as reference will have the ray origin's transform" is at odds with the documentation, which says: "Raycasts will not detect Colliders for which the Raycast origin is inside the Collider." So generally starting a rat inside your own collider is OK. The ray detects only places where it enters a collider, not places where it starts in or leaves one. \$\endgroup\$ – DMGregory Mar 19 '18 at 11:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.