# Question How to get the ground point of a Vector3?

Discussion in 'Scripting' started by billygamesinc, Mar 30, 2024.

1. ### billygamesinc

Joined:
Dec 5, 2020
Posts:
349
What I'm trying to do is spawn monsters/powerups on the ground. Here's how I'm doing it at the moment.

1. Find a starting point before randomizing, in this case it would be the player's position.
2. Randomize the z and x axis whilst using the player's Y position. Since I know that the Y is walkable/jumpable.
3. Raycast upward from that randomized point to find the ceiling point using the obstacle mask
4. From the ceiling point raycast downward to find the ground point
5. Overlap sphere to make sure there aren't any others of it's kind in that position.
I'm open to using NavMeshHit as well if it's easier.

Find Ground Point:
Code (CSharp):
2.     {
3.         //FindCeiling then
4.         float rayLength = 100;
5.         float castPosY = rayLength;
6.         if (Physics.Raycast(pos, Vector3.up, out RaycastHit ceilingHit, rayLength, obstacleMask))
7.         {
8.             castPosY = ceilingHit.point.y;
9.         }
10.         if (Physics.Raycast(new Vector3(pos.x, castPosY, pos.z), Vector3.down, out RaycastHit groundHit, 1000, obstacleMask))
11.         {
12.             return groundHit.point;
13.         }
14.         else
15.         {
17.             return Vector3.zero;
18.         }
19.     }
Find Random Position:
Code (CSharp):
2.     {
3.         float x = Random.Range(minDistance, maxDistance);
4.         float z = Random.Range(minDistance, maxDistance);
5.         int xModifier = Random.Range(0, 100) > 50 ? 1 : -1;
6.         int zModifier = Random.Range(0, 100) > 50 ? 1 : -1;
7.         randomPos = FindGroundPoint(new Vector3((startPos.x + x * xModifier), startPos.y, startPos.z + (z * zModifier)), obstacleMask);
9.         if (results == null || results.Length == 0)
10.         {
11.             return true;
12.         }
13.         else
14.         {
15.             return false;
16.         }
17.     }

2. ### ArachnidAnimal

Joined:
Mar 3, 2015
Posts:
1,936
I don't understand the point of raycasting upwards then downwards. Couldn't you just raycast downwards only?

PraetorBlue and Bunny83 like this.
3. ### spiney199

Joined:
Feb 11, 2021
Posts:
8,204
Yeah what's the actual question here?

You can probably just pick some arbitrarily high point and raycast infinitely downwards to find a point on the ground.

ArachnidAnimal and Bunny83 like this.
4. ### Bunny83

Joined:
Oct 18, 2010
Posts:
4,114
Right, the issue is probably that he thinks when his initial point is below the surface we should cast upwards. However that would not work because a raycast can only detect the surface of a collider from the outside. A raycast from the inside will not hit the collider.

ArachnidAnimal and spiney199 like this.
5. ### billygamesinc

Joined:
Dec 5, 2020
Posts:
349
Well in my case I would need to find a ceiling too, so two raycasts just to get a ground point. I was wondering if there was something built in navmesh or unity to do this with less code.

6. ### billygamesinc

Joined:
Dec 5, 2020
Posts:
349
In order to make sure it doesn't spawn on top of surfaces instead of under. Think of something like a doorway, i want it to spawn under the doorway

7. ### ArachnidAnimal

Joined:
Mar 3, 2015
Posts:
1,936
It still doesn't make sense to do an upward raycast. Do what spiney199 suggested above. Make sure the raycast can pass through everything except spawnable surfaces.

8. ### zulo3d

Joined:
Feb 18, 2023
Posts:
1,054
Code (CSharp):
1. using UnityEngine;
2. public class Spawner : MonoBehaviour // Spawn monsters somewhere off in the distance
3. {
4.     public GameObject monster;
5.
6.     void Start()
7.     {
8.         Vector3 pos=Quaternion.Euler(0,Random.Range(0,360),0)*Vector3.right*30; // Get a random distant point
9.         if (!Physics.SphereCast(transform.position,0.5f,pos,out RaycastHit hit,30)) // Nothing between us and the point?
10.             if (Physics.Raycast(transform.position+pos,Vector3.down,out hit,2)) // Ground below the point?
11.                 Instantiate(monster,hit.point+Vector3.up,Quaternion.identity); // RAWR!!
12.         Invoke("Start",0.5f); // keep doing it
13.     }
14. }

Last edited: Mar 31, 2024
billygamesinc likes this.
9. ### Bunny83

Joined:
Oct 18, 2010
Posts:
4,114
Well It does make sense when you understand the reason behind the two raycasts. Imagine a 3d level with several different hallways and levels. Choosing a new random location on the height of your player, that potential new location could be in a hallway at a higher elevation. So casting downwards wouldn't get you a proper position. So he first searches for the ceiling and then does another raycast from the ceiling down to find the floor. Though what doesn't really make sense to me is this default value:
Code (CSharp):
1. float castPosY = rayLength;
So when the potential position is below your current height, he would start the downward ray at an arbitrary absolute position that is equal to the ray length, so relative from absolute 0 rayLength upwards. Technically, depending on the level layout, that point at a height of 100 could still be below a potential valid location as this is not relative to the current player position but an absolute height in worldspace.

I would generally start with a single raycast downwards from the player center height to find the floor. If there is no floor below, do a raycast upwards to find the closest ceiling at this location and then do another raycast down to find the floor below that ceiling point. Just going up a fix amount and casting down would cause many issues if your level has multi layers / levels stacked on top of each other as you would always just hit the top floor.

Though just picking a random point in a rectangle around the player also isn't a great way to navigate anyways However this all depends on the level layout.

PraetorBlue likes this.
10. ### billygamesinc

Joined:
Dec 5, 2020
Posts:
349
Thanks for the detailed explanation. Getting the center position of the capsule collider seems like a way to approach this thanks!