Finally, here is a collection of small(ish) utility functions. None of them warrants a separate post. As usual, you can find this, and more, on my Bitbucket Repository.
First, since Transform.Find() only iterates over the direct children of a Transform, here are two functions to find objects in a hierarchy as DFS and BFS:
//Breadth-first search
public static Transform FindBroad(this Transform aParent, string aName) {
var result = aParent.Find(aName);
if (result != null)
return result;
foreach (Transform child in aParent)
result = child.FindBroad(aName);
if (result != null)
return result;
}
return null;
}
//Depth-first search
public static Transform FindDeep(this Transform aParent, string aName) {
foreach (Transform child in aParent) {
if (child.name == aName)
return child;
var result = child.FindDeep(aName);
if (result != null)
return result;
}
return null;
}
If you need the Canvas object for an UI element, you can use this:
public static Canvas GetCanvas(this Transform obj) {
Canvas canvas = obj.GetComponent<Canvas>();
while (canvas == null && obj.parent != null) {
obj = obj.parent;
canvas = obj.GetComponent<Canvas>();
}
return canvas;
}
This is a small function to copy the values from one Transform to another:
public static void Set(this Transform destination, Transform source, Space space = Space.Self) {
if (space == Space.Self) {
destination.localPosition = source.localPosition;
destination.localRotation = source.localRotation;
} else {
destination.position = source.position;
destination.rotation = source.rotation;
}
destination.localScale = source.localScale;
}
Here is a function that calculates a random direction vector within a cone around an initial direction. I use it, for example, to controll the spread of a gun.
public static Vector3 RandomInCone(this Vector3 dir, float openingAngle) {
Vector3 deviation = Random.insideUnitSphere;
dir = dir.normalized;
deviation -= Vector3.Dot(deviation, dir) * dir;
return (dir * Mathf.Cos(openingAngle) + deviation * Mathf.Sin(openingAngle)).normalized;
}
This here might be a bit niched, but it calculates the angle between a vector and the horizontal plane.
public static float Theta(this Vector3 vector) {
float y = vector.y;
float x = Mathf.Sqrt(vector.x*vector.x + vector.z*vector.z);
return Mathf.Atan2(y, x);
}
Lastly, here are two functions to calculate the length and the cost of a NavMeshPath (since Unity doesn’t provide a way to get these, yet). The cost-function can sometimes break at NavMesh borders.
public static float Length(this NavMeshPath path) {
if (path.corners.Length < 2) return 0;
float length = 0;
for (int i = 1; i < path.corners.Length; ++i) {
length += Vector3.Distance(path.corners[i], path.corners[i - 1]);
}
return length;
}
public static float Cost(this NavMeshPath path) {
if (path.corners.Length < 2) return 0;
float cost = 0;
NavMeshHit hit;
NavMesh.SamplePosition(path.corners[0], out hit, 0.1f, NavMesh.AllAreas);
Vector3 rayStart = path.corners[0];
int mask = hit.mask;
int index = IndexFromMask(mask);
for (int i = 1; i < path.corners.Length; ++i) {
while (true) {
NavMesh.Raycast(rayStart, path.corners[i], out hit, mask);
cost += NavMesh.GetAreaCost(index) * hit.distance;
if (hit.mask != 0) mask = hit.mask;
index = IndexFromMask(mask);
rayStart = hit.position;
if (hit.mask == 0) {
rayStart += (path.corners[i] - rayStart).normalized * 0.01f;
}
if (!hit.hit) break;
}
}
return cost;
}
Comments