Create an infinite loop

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

You’re going to have to clean up all those forum links all over your code for people to read it.

While I can’t really read the code, you must yield within a for loop inside an IEnumerator to keep it from becoming an infinite loop.

I think I see what you’re trying to do:

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);
    }
}
1 Like

I think that may be ecactly what I’m looking for! I’ll give it a test as soon as I can and hope it works!

Sorry to everyone about the links in the code. No clue how they got there

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

2 small and probably simple questions

  1. Will the loops int automatically reset to 0 after each time the code reaches the instantiate line?

  2. 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)

How about Transform.LookAt?

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;
1 Like

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

This works perfectly! With 1 dmall change, had to do the Tan for z rather than Sin for y. But othet than that small change it works just fine! Thanks!

Now I just need to instantiate with a rotation facing the player. Hm…

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:

GameObject newObject = Instantiate(spawnPosition, ...);
newObject.transform.LookAt(playerTransform);

Hm, actually t

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

Yes

Yes! The first one is exactly what I need! Thankfully my character remains at origin, so targeting is easy. Thanks so much!

You would think that kind of thing would be easier to find

1 Like

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.

I’ll give that a try and see what happens. Thanks!

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

Ah, now that’ll be your culprit.

For the algorithm to work across the XZ plane, simply replace this;

Vector3 dir = new Vector3(Mathf.Cos(angle), Mathf.Sin(angle), 0f);

with this;

Vector3 dir = new Vector3(Mathf.Cos(angle), 0f, Mathf.Sin(angle));

:slight_smile:

Clearly I should have paid more attention in math class haha.

It works perfectly! Thank you so much!

Wow it feels weird to have everything (currently) in my project working without error