0
\$\begingroup\$

I want the bounds (left wall and right wall) to follow the player's y position, a couple of times. However when I use this code, Unity freezez as soon as it runs, and I have to manually shut it down.

Any idea why?

public Transform bounds;

//in another function
StartCoroutine(Follow_Bounds(0));

IEnumerator Follow_Bounds(int a)
{
    yield return new WaitForSeconds(1f);
    while(a < 3)
    {
        StartCoroutine(Follow_Bounds(a + 1));
    }
   bounds.position = new Vector2(bounds.position.x, transform.position.y);
}
\$\endgroup\$
  • 2
    \$\begingroup\$ I'm not too familiar with Unity's coroutines, but your while(a < 3) most likely creates an infinite loop, because in its scope, a is never incremented. You might want to review the logic here. \$\endgroup\$ – Vaillancourt Dec 29 '19 at 14:10
  • \$\begingroup\$ change (a + 1) to (++a) \$\endgroup\$ – Evorlor Dec 30 '19 at 18:56
  • \$\begingroup\$ @Evorlor Wouldn't that generate something like 3 * 2 * 1 updates thought? \$\endgroup\$ – Vaillancourt Dec 31 '19 at 2:51
1
\$\begingroup\$

The loop:

while(a < 3)
{
    StartCoroutine(Follow_Bounds(a + 1));
}

Runs forever. a + 1 doesn't change a's value, it just passes a new value to the new coroutine instance.

You're likely crashing because each StartCoroutine call generates a helper object behind the scenes, since the loop runs forever, you'll run out of memory and crash.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

You want to move the bounds (only y position) with player after a few seconds of delay?

I do have a workaround that might work, it doesn't use recursion. You can use InvokeRepeating in this.

void SomeOtherFunction()
{
   InvokeRepeating("MoveBounds", InitialDelay, RepeatDelay);
}

void MoveBounds()
{
   bounds.position = new Vector2(bounds.position.x, transform.position.y);
}

SomeOtherFunction can be a Start() function as well. It will automatically repeat the MoveBounds function for you with every RepeatDelay Seconds (in your case it can be 1 seconds)

If you want to stop this function you can simply use CancelInvoke("MoveBounds"); and it will cancel the invoke function.

I hope it helps, here's the Documentation link for the function.

NOTE: It needs to be called only once, and it will repeat itself.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ This will work but I want to know why my way doesn't work because I dont see any problem at all. \$\endgroup\$ – ZozeR Dec 29 '19 at 14:09
  • \$\begingroup\$ I think the answer given by Vaillancourt sounds correct to me. Recursion usually consists of a base condition which was not met and it was looping infinitely. \$\endgroup\$ – Hasnain NoOrani Dec 30 '19 at 10:18
0
\$\begingroup\$

I don't have much experience with Unity and its coroutines, so things might not be completely exact.

You have something like infinite nested loops.

StartCoroutine(Follow_Bounds(0));

IEnumerator Follow_Bounds(int a)
{
    yield return new WaitForSeconds(1f);
    while(a < 3)
    {
        StartCoroutine(Follow_Bounds(a + 1));
    }
    bounds.position = new Vector2(bounds.position.x, transform.position.y);
}

Could conceptually be expanded to something like this:

StartCoroutine(Follow_Bounds(0));

IEnumerator Follow_Bounds(int a) // With a == 0
{
    yield return new WaitForSeconds(1f);
    while(0 < 3)
    {
        yield return new WaitForSeconds(1f);
        while(1 < 3)
        {
            yield return new WaitForSeconds(1f);
            while(2 < 3)
            {
                yield return new WaitForSeconds(1f);
                while(3 < 3)
                {
                    // This will not be called
                    // yield return new WaitForSeconds(1f);
                    // StartCoroutine(Follow_Bounds(a + 1));
                }
                bounds.position = new Vector2(bounds.position.x, transform.position.y);
            }
            bounds.position = new Vector2(bounds.position.x, transform.position.y);
        }
        bounds.position = new Vector2(bounds.position.x, transform.position.y);
    }
    bounds.position = new Vector2(bounds.position.x, transform.position.y);
}

In no situation here you make sure that the end condition is met. When your program freezes, or hangs, it's generally a symptom of an infinite loop.

If you want to use recursion, you could modify your code to something like:

StartCoroutine(Follow_Bounds(0));

IEnumerator Follow_Bounds(int a)
{
    if(a < 3)
    {
        StartCoroutine(Follow_Bounds(a + 1));
        yield return new WaitForSeconds(a + 1f);
        bounds.position = new Vector2(bounds.position.x, transform.position.y);
    }
}

Things to note here: we "loop" using the recursion, not a "code" loop; all your 'wait' are started upfront, with a different delay; we have a clear end condition.

However, this is overly complicated code. Recursive code should be avoided when possible, and should be explained and justified in the comments when unavoidable. If you can use an API or language construct instead, use that. (Another answer covers this.) If not, use a loop instead.

So the preferred algorithm to complete such a task is API or language construct > loop > recursive code.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I'd appreciate if the person who downvoted left a comment so that the answer could be improved :) \$\endgroup\$ – Vaillancourt Dec 31 '19 at 4:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.