Utilities: Bits and Bobs

0

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

Your email address will not be published. Required fields are marked *