# Question Getting height from the ground using Raycasting - returning y = 0 no matter the height!

Discussion in 'Scripting' started by wingsneon, Feb 5, 2024.

1. ### wingsneon

Joined:
Jul 5, 2018
Posts:
23
Hello people, I'm trying to make a function that teleports a gameobject to a random position 3D, in a random X Z direction, but the height (y) must be a fixed height from the ground.

The problem is in the function that should manage the height:
The function will return a Vector3 in which it's
``y``
will be the distance from the
``origin``
to the ground.
It casts a ray that starts at
``origin``
, pointing down, information goesto hit, and the distance is an infinite value (I might change later to big fixed value).
It returns 0 everytime,

Code (CSharp):
1. Vector3 GetGroundHeight(Vector3 origin)
2.     {
3.         Vector3 pos = new Vector3(0, 0, 0);
4.
5.         RaycastHit hit;
6.         if (Physics.Raycast(origin, Vector3.down, out hit, Mathf.Infinity, groundMask))
7.         {
8.             print(\$"ground pos: {hit.point}");
9.             pos.y = hit.point.y;
10.         }
11.         return pos;
12.     }
Example of the location of the origin, ignore the gizmo's raycast, it has nothing to do with the GetGroundHeight function.

What it returns in console (y = 0):

I would like for it to return the actual height between the origin and the ground!
If someone's curious about how this could help making the height of the gameobject always a fixed position, no matter the ground height variation - my goal is to get the distance between the gameobject and the ground through the raycast, then I'll set the gameobject height (y) to subtract from the raycast result , which will make the gameobject stick to the ground, then I just add a desired height value like height = 1 or 3.

2. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
38,656
Are you always hitting something like yourself or something up in the air??

You can print out the
``hit.transform.name``
to see.

BTW, I do this same process for my spawnpoint scripts too: I have an editor script that finds all spawnpoints and tries to place them on a surface. I did it by:

In a loop:
- lift 1 meter
- cast down 2 meters
- did I hit something? we're done, use that hit
- now increase the lift by 1 meter and the cast by 2 meters

Found the outer wrapper code:

Code (csharp):
2.     static void CastPlayerSpawnsToGround()
3.     {
4.         var candidates = SpaceFlightPlayerSpawnFinder.FindPlayerSpawns(true);
5.
6.         int debugCount = 0;
7.         foreach( var tr in candidates)
8.         {
9.             Vector3 pos = tr.position;
10.
11.             bool hitGround = SpawnUtilities.ProgressiveLiftAndCastDown( ref pos);
12.
13.             if (hitGround)
14.             {
15.                 tr.position = pos;
16.                 debugCount++;
17.             }
18.
19.             if (!hitGround)
20.             {
21.                 Debug.LogWarning( "EditorCastPlayerSpawnsToGround.CastPlayerSpawnsToGround(): Failed to cast!");
22.                 Debug.LogWarning( "Failed object was named " + tr.name);
23.             }
24.         }
25.         Debug.Log( "Cast a total of " + debugCount.ToString() + " to the ground.");
26.     }
And here was my caster:

Code (csharp):
1. using System.Collections;
2. using System.Collections.Generic;
3. using UnityEngine;
4.
5. public static class SpawnUtilities
6. {
7.    public static bool ProgressiveLiftAndCastDown( ref Vector3 position, out Vector3 normal)
8.    {
9.        Vector3 pos = position;
10.
11.        normal = Vector3.up;
12.
13.        bool hitGround = false;
14.
15.        float castDistance = 0.0f;
16.
17.        for (int tries = 0; tries < 250; tries++)
18.        {
19.            pos += Vector3.up * 1.0f;
20.
21.            castDistance += 2.0f;
22.
23.            Ray ray = new Ray( pos, Vector3.down);
24.            RaycastHit rch;
25.            if (Physics.Raycast( ray, out rch, castDistance))
26.            {
27.                hitGround = true;
28.
29.                position = rch.point;
30.
31.                normal = rch.normal;
32.
33.                var s = "SpawnUtilities.ProgressiveLiftAndCastDown:hit '" + rch.collider.name + "'";
34.                s += System.String.Format( ": pos:{0} norm:{1}", position, normal);
35.                Debug.Log( s);
36.
37.                break;
38.            }
39.        }
40.
41.        return hitGround;
42.    }
43.
44.    public static bool ProgressiveLiftAndCastDown( ref Vector3 position)
45.    {
46.        Vector3 normalDummy = Vector3.zero;
47.
48.        bool hitGround = ProgressiveLiftAndCastDown( ref position, out normalDummy);
49.
50.        return hitGround;
51.    }
52. }

Above code from Jetpack Kurt Space Flight:

Last edited: Feb 6, 2024
wingsneon likes this.
3. ### wingsneon

Joined:
Jul 5, 2018
Posts:
23
Did that, it's hitting the right layer. I used
``Layermask groundLayer;``
then set the layermask in the inspector to avoid having to do bit shifting

I also added a yellow debug ray to see the hit trajectory, and surprisingly, it seems that it is working properly, though it's returning 0 for some reason
Code (CSharp):
1.  Vector3 GetGroundHeight(Vector3 origin)
2.     {
3.         Vector3 pos = new Vector3(0, 0, 0);
4.         RaycastHit hit;
5.
6.         if (Physics.Raycast(origin, Vector3.down, out hit, Mathf.Infinity, groundMask.value))
7.         {
8.             print(\$"ground pos: {hit.point}");
9.             Debug.DrawRay(origin, Vector3.down * hit.distance, Color.yellow);
10.             Print(pos);
11.         }
12.         return pos;
13.     }
The ray seems to be working properly!

But then... (
``Print(pos)``
)

Last edited: Feb 6, 2024
4. ### spiney199

Joined:
Feb 11, 2021
Posts:
7,797
You never assign anything to
``pos``
...

wingsneon and Kurt-Dekker like this.
5. ### Kurt-Dekker

Joined:
Mar 16, 2013
Posts:
38,656
I think you took out the
``pos.y = hit.point.y``

I still have no idea why your first post code wouldn't work... I suspect something else is setting the y to zero outside of the first function...

6. ### wingsneon

Joined:
Jul 5, 2018
Posts:
23
I already solved it, really don't know why it wasn't working with hit.point.y, but instead I used hit.distance

so
``height = hit.distance``
did the trick.

Here's my code in case someone's wondering:

Code (CSharp):
2.     // Returns the distance between the position of origin and ground
3.     float GetGroundDistance(Vector3 origin)
4.     {
5.         float height = 3;
6.         RaycastHit hit;
7.         if (Physics.Raycast(origin, Vector3.down, out hit, Mathf.Infinity, groundMask.value))
8.         {
9.             height = hit.distance;
10.         }
11.         return height;
12.     }
13.
14.
15.     private Vector3 thisCube; // script's attached to this obj
16.     private Vector3 randomPos = new Vector3(0f, 0f, 0f);
17.     // Generates a random position in Z and X axis
18.     // keeping a certain height from the ground
19.     public Vector3 GetRandomPos(float setHeight)
20.     {
21.
22.         // Generates a random position within the gameobject volume
23.         Vector3 cubePosition = gameObject.transform.position;
24.         float randomX = Random.Range(cubePosition.x -thisCube.x / 2f, cubePosition.x + thisCube.x / 2f);
25.         float randomZ = Random.Range(cubePosition.z-thisCube.z / 2f, cubePosition.z+thisCube.z / 2f);
26.
27.         // I opted to update the randomPos value, instead of creating a new vector everytime.
28.         randomPos.x = randomX;
29.         randomPos.z = randomZ;
30.         randomPos.y = 3f; // presetting this value fixed it from returning different y variations.
31.         randomPos.y = - GetGroundDistance(randomPos) + setHeight; // Stick it to the ground then apply height
32.
33.         return randomPos;
34.     }
35.

Last edited: Feb 8, 2024
7. ### JoshuaMcKenzie

Joined:
Jun 20, 2015
Posts:
916
You were confusing what "hit.point" is. Its just telling you the world coordinate where the impact happened, its not the local offset from your raycast origin.