Hello everyone, I would like to arrange some prefabs (eight to be more specific) in a circular formation around a center point, all equally spaced. They could be instantiated or just moved, I’m just trying to have them in circular formation. I’ve tried several supposed solutions from around the internet but each to no avail. What’s the right thing to do?
Explanation
If you don’t really want to know, just skip to the final code snippet.
The circumference of a circle is 2 * Pi * r
but we can ignore the radius in this case since we only want the spread around the circle, making the function 2 * Pi
.
Let’s say we have 5 enemies. This means each enemy must 2 * Pi / 5
distance around the circle (Radians) away from each other.
We’ll use num
to denote number of enemies making the formula: 2 * Pi / num
.
If we were to loop through each enemy i
, the position of the current one around the circle would be the previous position plus 2 * Pi / num
.
Meaning to determine the exact radians we can use 2 * Pi / num * i
.
for (int i = 0; i < num; i++){
/* Distance around the circle */
var radians = 2 * MathF.Pi / num * i;
...
}
We only have the radians now, but in Unity, we don’t use radians, so we need to convert radians into a direction (Vector3) and position (Vector3).
To do that, we need to find both the vertical and horizontal positions. For vertical, we can use Sin and for horizontal we can use Cos.
We can add the new Vector3 to the center point to get the spawn direction relative to the center point and then multiply it by radius.
/* Get the vector direction */
var vertical = MathF.Sin(radians);
var horizontal = MathF.Cos(radians);
var spawnDir = new Vector3 (horizontal, 0, vertical);
/* Get the spawn position */ /* Get the spawn position */
var spawnPos = point + spawnDir * radius; // Radius is just the distance away from the point
Now that we have the spawn pos we can simply spawn the enemy, rotate it to look at the player, and then adjust height, so the enemies don’t fall out of the world.
/* Now spawn */
var enemy = Instantiate (enemyPrefab, spawnPos, Qaurtenion.Identity) as GameObject;
/* Rotate the enemy to face towards player */
enemy.transform.LookAt(point);
/* Adjust height */
enemy.transform.Translate (new Vector3 (0, enemy.transform.LocalScale.y / 2, 0));
Full Solution
This is what it will look like if we put it all together:
public GameObject enemyPrefab;
public void CreateEnemiesAroundPoint (int num, Vector3 point, float radius) {
for (int i = 0; i < num; i++){
/* Distance around the circle */
var radians = 2 * MathF.Pi / num * i;
/* Get the vector direction */
var vertical = MathF.Sin(radians);
var horizontal = MathF.Cos(radians);
var spawnDir = new Vector3 (horizontal, 0, vertical);
/* Get the spawn position */
var spawnPos = point + spawnDir * radius; // Radius is just the distance away from the point
/* Now spawn */
var enemy = Instantiate (enemyPrefab, spawnPos, Qaurtenion.Identity) as GameObject;
/* Rotate the enemy to face towards player */
enemy.transform.LookAt(point);
/* Adjust height */
enemy.transform.Translate (new Vector3 (0, enemy.transform.LocalScale.y / 2, 0));
}
}
Hope this helps. If you have any questions, let me know.
An easier way
With normalizing the result you will get a point on circle diameter
Random.insideUnitCircle.normalized * radius;
It is a sample how I did this:
var rotationStep = 360 / _twisterAmount;
for (int i = 0; i < _twisterAmount; i++)
{
var ang = rotationStep * i;
var position = new Vector3(MathF.Cos(
ang * Mathf.Deg2Rad),
0,
MathF.Sin(ang * Mathf.Deg2Rad))*_distanceToOrigin;
var tw = Instantiate(_twisterPrefab,_root);
tw.transform.localPosition = position;
}
A big friend of mine help me make. I hope it help.
That video below help a lot too:
Here’s @Cornelis-de-Jager’s full solution answer but without the typos…
public void CreateEnemiesAroundPoint(int num, Vector3 point, float radius)
{
for (int i = 0; i < num; i++)
{
/* Distance around the circle */
var radians = 2 * Mathf.PI / num * i;
/* Get the vector direction */
var vertical = Mathf.Sin(radians);
var horizontal = Mathf.Cos(radians);
var spawnDir = new Vector3(horizontal, 0, vertical);
/* Get the spawn position */
var spawnPos = point + spawnDir * radius; // Radius is just the distance away from the point
/* Now spawn */
var enemy = Instantiate(enemyPrefab, spawnPos, Quaternion.identity) as GameObject;
/* Rotate the enemy to face towards player */
enemy.transform.LookAt(point);
/* Adjust height */
enemy.transform.Translate(new Vector3(0, enemy.transform.localScale.y / 2, 0));
}
}
For anyone struggling with overlapping objects change
var radians = 2 * MathF.Pi / num * i;
To
var radians = i* 2 * MathF.Pi / num ;
This solves the division by 0 error, plus spaces the objects like theyre supposed to be placed
@Cornelis-de-Jager why dont you check your code before post answer , so many mystakes in it.
vertrical - vertcial .Mathf not MathF etc…