Instantiate object in random position on 'donut' shaped platform

Basically I want objects to periodically instantiate in random positions on this platform. This wasn’t a problem, because I just used the built-in “Random.insideUnitCircle.” However, now I have a circular platform with a hole in the middle, and I do not want it to instantiate over the hole. Even worse, later on I have a platform with two holes in it.

I have a basic concept down: I have to subtract the area of that hole from the area of the entire platform, then spawn it somewhere in that area…I’m just not really sure how to go about that with the code. I could do it using loops to just constantly put a random spot until it is not a spot in that hole, but there HAS to be some way to do this using a simple line of Geometry.

Thank you in advance :slight_smile:

For one hole:
Spawn at the center of the hole then pick a range angle and move a random distance from the minimum requirement to the maximum requirement forward

var angle : float = Random.Range(0f, 360f);
var dist : float = Random.Range(1f, 3f);

transform.Rotate(Vector3(0, angle, 0));
transform.Translate(Vector3(dist, 0, dist));

For two holes: I’ll have to dig out an old book…

Solving it with math is fairly straight forward, but since you are going to have two holes (and I assume the holes will not be in the center), why not figure out a solution that works for that situation now. One common approach is to just keep generating random values until you get one that works.

So here is an example:

#pragma strict

var holeLocalPos = Vector3(0,0);
var holeRadius = 1.0;
var platformRadius = 3.0;

function FindPos() {
	var pos : Vector3;
	for (var i = 0; i < 1000; i++) {
		pos = Random.insideUnitCircle * platformRadius;
		if (Vector3.Distance(pos, holeLocalPos) > holeRadius) {
			return pos;
		}
	}
	return pos;
}

FindPos() will return a valid local position. You will need to either add transform.position to the point (non-rotated or scaled platform), or use Transform.TransformPoint() to find the world position to spawn your object.

When you get two holes, just add a bit more data and change the check to:

	if ((Vector3.Distance(pos, holeLocalPos1) > holeRadius1) && (Vector3.Distance(pos, holeLocalPos2) > holeRadius2)) {

Note I use a for() loop that limits the tries. This prevents the code from hanging if I happen to code an impossible criteria. With the current code it would be difficult to hang, but imagine you add a new condition tomorrow that not only must it be on the ring, but the position must not overlap an existing object.