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,
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.
Thanks in advance!
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:
[MenuItem( "Tools/CastPlayerSpawnsToGround")]
static void CastPlayerSpawnsToGround()
{
var candidates = SpaceFlightPlayerSpawnFinder.FindPlayerSpawns(true);
int debugCount = 0;
foreach( var tr in candidates)
{
Vector3 pos = tr.position;
bool hitGround = SpawnUtilities.ProgressiveLiftAndCastDown( ref pos);
if (hitGround)
{
tr.position = pos;
debugCount++;
}
if (!hitGround)
{
Debug.LogWarning( "EditorCastPlayerSpawnsToGround.CastPlayerSpawnsToGround(): Failed to cast!");
Debug.LogWarning( "Failed object was named " + tr.name);
}
}
Debug.Log( "Cast a total of " + debugCount.ToString() + " to the ground.");
}
And here was my caster:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public static class SpawnUtilities
{
public static bool ProgressiveLiftAndCastDown( ref Vector3 position, out Vector3 normal)
{
Vector3 pos = position;
normal = Vector3.up;
bool hitGround = false;
float castDistance = 0.0f;
for (int tries = 0; tries < 250; tries++)
{
pos += Vector3.up * 1.0f;
castDistance += 2.0f;
Ray ray = new Ray( pos, Vector3.down);
RaycastHit rch;
if (Physics.Raycast( ray, out rch, castDistance))
{
hitGround = true;
position = rch.point;
normal = rch.normal;
var s = "SpawnUtilities.ProgressiveLiftAndCastDown:hit '" + rch.collider.name + "'";
s += System.String.Format( ": pos:{0} norm:{1}", position, normal);
Debug.Log( s);
break;
}
}
return hitGround;
}
public static bool ProgressiveLiftAndCastDown( ref Vector3 position)
{
Vector3 normalDummy = Vector3.zero;
bool hitGround = ProgressiveLiftAndCastDown( ref position, out normalDummy);
return hitGround;
}
}
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
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:
public LayerMask groundMask;
// Returns the distance between the position of origin and ground
float GetGroundDistance(Vector3 origin)
{
float height = 3;
RaycastHit hit;
if (Physics.Raycast(origin, Vector3.down, out hit, Mathf.Infinity, groundMask.value))
{
height = hit.distance;
}
return height;
}
private Vector3 thisCube; // script's attached to this obj
private Vector3 randomPos = new Vector3(0f, 0f, 0f);
// Generates a random position in Z and X axis
// keeping a certain height from the ground
public Vector3 GetRandomPos(float setHeight)
{
// Generates a random position within the gameobject volume
Vector3 cubePosition = gameObject.transform.position;
float randomX = Random.Range(cubePosition.x -thisCube.x / 2f, cubePosition.x + thisCube.x / 2f);
float randomZ = Random.Range(cubePosition.z-thisCube.z / 2f, cubePosition.z+thisCube.z / 2f);
// I opted to update the randomPos value, instead of creating a new vector everytime.
randomPos.x = randomX;
randomPos.z = randomZ;
randomPos.y = 3f; // presetting this value fixed it from returning different y variations.
randomPos.y = - GetGroundDistance(randomPos) + setHeight; // Stick it to the ground then apply height
return randomPos;
}
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.