Last active
June 3, 2020 07:15
-
-
Save louis030195/4cc2dd8a708cad24d58028e07480eb73 to your computer and use it in GitHub Desktop.
Unity helper to spawn object above ground or try to spawn objects above ground in a random sphere while keeping a given distance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class Spatial | |
{ | |
/// <summary> | |
/// Return position above ground relatively from the prefab size | |
/// Global position | |
/// </summary> | |
/// <param name="position"></param> | |
/// <param name="prefabHeight">Prefab height needed in order to place well on top of ground</param> | |
/// <param name="transform">Transform parent</param> | |
/// <param name="layerMask">Layers to ignore</param> | |
/// <returns></returns> | |
public static Vector3 PositionAboveGround(this Vector3 position, | |
float prefabHeight = 1f, | |
Transform transform = null, | |
LayerMask layerMask = default) | |
{ | |
var p = position; | |
if (transform != null) p += transform.position; | |
// Current position is below ground | |
if (Physics.Raycast(p, Vector3.up, out var hit, Mathf.Infinity, ~layerMask)) | |
{ | |
p.y += hit.distance + prefabHeight * 0.5f; | |
return p; | |
} | |
// Current position is above ground | |
if (Physics.Raycast(p, Vector3.down, out hit, Mathf.Infinity, ~layerMask)) | |
{ | |
p.y -= hit.distance - prefabHeight * 0.5f; | |
return p; | |
} | |
// There is no ground above or below, outside map | |
return Vector3.zero; | |
} | |
/// <summary> | |
/// This function will find a position to spawn above ground and far enough from other objects of the given layer | |
/// Returns Vector3 zero in case it couldn't find a free position | |
/// </summary> | |
/// <returns></returns> | |
public static Vector3 RandomPositionAroundAboveGroundWithDistance(this Vector3 center, | |
float radius, | |
LayerMask layerMask, | |
float distance, | |
float prefabHeight = 1f, | |
Transform transform = null, | |
int numberOfTries = 10) | |
{ | |
if (distance > radius) | |
{ | |
Debug.LogError("Distance must be inferior to radius"); | |
return Vector3.zero; | |
} | |
var tries = 0; | |
// While we didn't find a free position | |
while (tries < numberOfTries) | |
{ | |
// We pick a random position around above ground | |
var newPos = center + Random.insideUnitSphere * radius; | |
newPos = newPos.PositionAboveGround(prefabHeight, transform); | |
if (newPos == Vector3.zero) // Outside map | |
{ | |
tries++; | |
continue; | |
} | |
// Then we check if this spot is free (from the given layer) | |
var hitColliders = Physics.OverlapSphere(newPos, distance, layerMask); | |
// If no objects of the same layer is detected, this spot is free, return | |
if (hitColliders.Length == 0) return newPos; | |
tries++; | |
} | |
return Vector3.zero; | |
} | |
} |
Author
louis030195
commented
Jun 2, 2020
Usage:
var myCenter = new Vector3(10, 0, 66);
var randomPositionWithinACircleOfRadius = 10f;
var iWantObjectToKeepADistanceOf = 1f;
var p = myCenter.RandomPositionAroundAboveGroundWithDistance(randomPositionWithinACircleOfRadius,
LayerMask.GetMask("MyObjectLayerThatIWantToKeepDistanceFrom"),
iWantObjectToKeepADistanceOf);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment