0
votes

I have met a strange problem when using Coroutine in Unity. Before modification, my code is as the following:

IEnumerator Destory()
{
    yield return new WaitForSeconds(destoryDelay);
    yield return StartCoroutine(Timer.Start(0.5f, false, gameManager.EnableBtnSummon));
    GameObject.Destroy(this.gameObject);
}

Time.Start() is an utility written by myself and used for delay invoke.

public static IEnumerator Start(float duration, bool repeat, Action callback)
{
    do
    {
        yield return new WaitForSeconds(duration);                
        if (callback != null)
            callback();
    } while (repeat);
}

Because Time.Start() includes WaitForSeconds(), so I decided to modify above code as the following:

IEnumerator Destory()
{
    //yield return new WaitForSeconds(destoryDelay);
    yield return StartCoroutine(Timer.Start(destoryDelay+0.5f, false, gameManager.EnableBtnSummon));
    GameObject.Destroy(this.gameObject);
}

Unfortunately, console throw an error:

ArgumentException: Value does not fall within the expected range.

gameManager.EnableBtnSummon is just an Action processing game logic. After debug, i make sure that error occurred before this function run. But i will show it for more clues.

public void EnableBtnSummon()
{
    //will not reach this!
    print("Enable Button Summon");
    //if detecting monster, change relative sprite of monster medal
    if (currentMonsterIndex != -1)
    {
        Image captureMonsterSprite = monsterMedalList.transform.GetChild(currentMonsterIndex).GetComponent<Image>();
        captureMonsterSprite.sprite = mosnterExplicitMedalList[currentMonsterIndex];

        Image gameOverMonsterSprite = gameOverMonsterList.transform.GetChild(currentMonsterIndex).GetComponent<Image>();
        gameOverMonsterSprite.sprite = mosnterExplicitMedalList[currentMonsterIndex];

        currentMonsterIndex = -1;
        captureMonsterCount++;
    }

    if (captureMonsterCount == monsterIndexDictionary.Count) return;

    var summonAnimator = btnSummon.GetComponent<Animator>();
    summonAnimator.SetBool("isSearch", false);

    btnSummon.enabled = true;
    btnExit.enabled = true;

    fogParticleSystem.Play();
}

I cannot understand it, could someone tell me what happens? thx...

1
Just try to format the code in your question. Also, where are you getting this error? How is gameManager declared?Programmer
It would be nice if you could isolate your arguments to see which one is causing the issue. You should declare each as local variable, then you call Debug.Log to verify their value before sending them.MadStark
Thanks for comments and modification, it's my first time to use StackOverflow, so it may be ambiguous.Luren Wang
Welcome to SO. You can use @username to reply to specific users. I asked how gameManager and EnableBtnSummon are declared. If you don't mind showing that, that would be awesome. Maybe post the class itself .... These are required to tell what's going on.Programmer
@Programmer thanks again! I have update my question, but i think gameManager doesn't matter because error occurred even before Action is invoked.Luren Wang

1 Answers

6
votes

The exception:

ArgumentException: Value does not fall within the expected range.

is happening on this line of code:

yield return StartCoroutine(MoveTowards.Start(destoryDelay + 0.5f, false, gameManager.EnableBtnSummon));

This has nothing to do with StartCoroutine as the title of the question says. The source of the problem is the MoveTowards.Start coroutine function. The third parameter(Action callback) that is passed into it is the issue.

The issue is that you are passing null to the third parameter of the MoveTowards.Start function. Since you are passing gameManager.EnableBtnSummon to that third parameter, this means that the gameManager variable is null.

You can verify this by adding Debug.Log(gameManager) before that line of code. The output should be "null" in the Console tab.

FIX:

Initialize the gameManager variable:

Name the GameObject your GameManager script is attached to "ManagerObj" then use the simple code below to initialize the gameManager variable.

GameManager gameManager;

void Awake()
{
    gameManager = GameObject.Find("ManagerObj").GetComponent<GameManager>();
}

Note:

Rename your Start function to something else as there is already Unity built in function named "Start" and "Awake". You need to change the name to something else but this is not the problem.