I’m trying to spawn enemies in my game, but I want to make sure that they are outside a specific radius from my player. I’m having a lot of trouble figuring out how to properly set up a loop, both in the programmimg and in the logic. I feel like I’m suoer close but can’t figure out just that one small piece I’m missing.
Basically I’m having a number of enemies spawned, for each number I will find a vector3 position but if the vector3 generated is within the radius to the player I want it to find a new position and check the distance again. Basically doing this forever until a vector3 is found that is outside the radius.
I’ve tried using different for loops but I honestly can’t wrap my head around the logic needed to make it work.
I simplified some of the parts of the code
IEnumerator Spawn (){
for (int i = 0; i < alienCount; i++)
{
Vector3 spawnPosition = new Vector3 ();
float dist = player.transform.position - spawnPosition).magnitude[/URL];
if (dist > radius)
{
Instantiate(//enemy at location);
}
else
{
spawnPosition = new Vector3 (//long code to find new vector3);
}
yield return new WaitForSeconds (spawnWait);
}
No idea why a bunch of links got randomly shoved into my code. I definitely didn’t add them since I am typing all this on my phone
IEnumerator Spawn() {
float minDistanceFromPlayer = 10;
float spawnRadius = 100;
bool foundPosition;
Vector3 randomPosition;
Vector3 spawnPosition;
for(int i = 0; i < alienCount; i++) {
// while a valid position has not been found (this will lock up Unity if no position is found)
while(!foundPosition) {
// get a position
randomPosition = Random.insideUnitCircle * spawnRadius;
// if the distance between that new position and the player is greater than the minimum
if(Vector2.Distance(randomPosition, transform.position) > minDistanceFromPlayer) {
spawnPosition = randomPosition;
foundPosition = true; // breaks the loop
}
}
// spawn it at the position
Instantiate(alien, spawnPosition, Quaternion.identity);
yield return new WaitForSeconds(spawnWait);
}
}
Here’s a hacky way to prevent lock-ups during testing:
IEnumerator Spawn() {
float minDistanceFromPlayer = 10;
float spawnRadius = 100;
bool foundPosition = false;
Vector3 randomPosition;
Vector3 spawnPosition;
int failSafe = 100;
int loops = 0;
for(int i = 0; i < alienCount; i++) {
while(!foundPosition) {
if(loops < failSafe) {
loops++;
} else {
print("infinite loop broken");
break;
}
// get a position
randomPosition = Random.insideUnitCircle * spawnRadius;
// if the distance between that new position and the player is greater than minimum
if(Vector2.Distance(randomPosition, transform.position) > minDistanceFromPlayer) {
spawnPosition = randomPosition;
foundPosition = true; // breaks loop
}
}
// spawn it at the position
Instantiate(alien, spawnPosition, Quaternion.identity);
yield return new WaitForSeconds(spawnWait);
}
}
It appears to be working perfectly as far as constantly loop until finding a valid spawn position! Thabks!
I do have ome small error where after it does find a valid position, it will keep spawning in the same spot and never change. Seems like a small problem so I’ll poke around and try to fix that.
I also had to change the Random.insideUnitCircle to the code I used previously. That one was putting the position in a sphere, but the code I have keeps it on the plane I have. But easy fix!
I also had to change the declaration at the top to:
Vector3 spawnPosition = new Vector3 ();
Not sure why it makes me have to put it that way
Will the loops int automatically reset to 0 after each time the code reaches the instantiate line?
How can I instantiate my prefab with it facing my player. I’m looking around but I’m not finding anything online to set the quaternion to be looking at the player (who is at 0,0,0)
Actually, that brute force approach is really in-efficient. A better way would be to replace the loop with a little math instead. Something like this;
// your min/max radius
float minRadius = 1f, maxRadius = 10f;
// random angle between 0-360 degrees
float angle = Random.value * (2f * Mathf.PI);
// direction from angle using a little trig
Vector3 dir = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0f);
// random radius between min and max
float radius = Random.Range(minRadius, maxRadius);
// position from direction and radius
spawnPosition = dir * radius;
I try to replace the Quaternion.identity with transform.LookAt and it never seems to want to work. Maybe I’m not inputting the code properly? It seems to always have an error mo matter how I align it
That mighr actually work as well! I’ll have to give that one a try. Despite me knowing knowing the math, the code does seem far easier to impliment, not to mention easier to run. I’ll try it out and see where I get
Is your player always at the origin? You already have the direction that you spawned the enemy relative to the origin, as “dir”. So if your spawned objects are using the Z axis as forward, you can pass this rotation into the Instantiate function:
Quaternion.LookRotation(-dir, Vector3.up)
Where -dir is which way to point the Z axis, and Vector3.up is a hint vector for the Up direction.
Or as previously mentioned in the thread, you can use transform.LookAt in the same way with a reference to the new object’s transform ie:
Hm there seems to be 1 small issue, its all spaening correctly, but the ranges are weird. Every once in a while 1 will spawn really far away. Not sure why that would happen
Have you solved this? If not, add a Debug.Log(radius) and observe its value when you see the issue. It should of course stick to your min/max radius settings.
So I set the min and max dist values to be the same so that way the radius that is used is always the same. Interestingly, the enemies that I am instantiating still appear at different distances from my player. From everything I can see, it shouldn’t be doing that