StartCoroutine is being called so many times (C# Unity)

两盒软妹~` 提交于 2019-12-02 17:14:53

问题


I'm creating a Pop up menu Option in Unity. Now my Problem here is that the coroutine i made in void update is being called so many times. What i mean by that is on my Unity Console the Debug.Logs are incrementing . It should not right because its already coroutine. Could some help me understand more coroutine and help me solve my little problem .

Here is my code:

[SerializeField]
GameObject Option;
[SerializeField]
Button btn,btn2;
[SerializeField]
GameObject open, close;

[SerializeField]
GameObject[] opt;
bool startFinding = false;
void Start()
{
    Option.SetActive(false);
    Button popUp = btn.GetComponent<Button>();
    Button popUp2 = btn2.GetComponent<Button>();
    popUp.onClick.AddListener(PopUpOption);
    popUp2.onClick.AddListener(ClosePopUp);


}

void Update()
{
    if (startFinding)
    {
        StartCoroutine(GameOptions());
    } 
}

IEnumerator GameOptions()
{

    //Get All the tags
    opt = GameObject.FindGameObjectsWithTag("MobileOptions");

    if (opt[0].GetComponent<Toggle>().isOn == true && opt[1].GetComponent<Toggle>().isOn == true)
    {
        Debug.Log("Disable first the check box then choose only 1 option between" + "'rendering'"+ "and" + "'livestreaming'");
    }
    //Livestreaming
    if (opt[0].GetComponent<Toggle>().isOn == true)
    {
        Debug.Log("Livestreaming Activate");
    } else 
    {
        Debug.Log("Livestreaming Deactivate");
    }
    //Rendering
    if (opt[1].GetComponent<Toggle>().isOn == true)
    {
        Debug.Log("Rendering Activate");
    } else
    {
        Debug.Log("Rendering Deactivate");
    }
    //Fog

    if (opt[2].GetComponent<Toggle>().isOn == true)
    {
        Debug.Log("Fog Activated");
    } else
    {
        Debug.Log("Fog Deactivated");
    }

    //Camera Effect
    if (opt[3].GetComponent<Toggle>().isOn == true)
    {
        Debug.Log("Camera Effect Activated");
    } else {
        Debug.Log("Camera Effect Deactivated");
    }
        yield return null;
}

void PopUpOption()
{
    startFinding = true;
    //Disable The Mobile Option Button
    open.SetActive(false);
    //Enable the Close Option Button
    close.SetActive(true);
    //activate the Mobile Options
    Option.SetActive(true);

}

void ClosePopUp()
{
    startFinding = false;
    //eanble the mobile option button
    open.SetActive(true);
    //disable the close option button
    close.SetActive(false);
    //deactivate the Mobile Option
    Option.SetActive(false);
}

回答1:


Here is how coroutines work:

Let's say I have a couroutine function called MyRoutine (in your case, you called it GameOptions)

private IEnumerator MyRoutine()

Then, anywhere in my code, calling

StartCoroutine(MyRoutine));

Is going to simply call MyRoutine like any usual method. So if you call it in update, it will be called all the time, as any method would. This is not what you want. What make coroutines special is that you can use the yield keyword in them. There are many ways to use it but the most used (and simple) one is to do yield return null

yield return null means "Stop this coroutine, but resume the execution on next frame". You don't need to call any other function (certainly not StartCoroutine). The execution will resume next frame.

To go back to what you posted in your question, you wrote yield return null at the end. So your method is executing, and just at the end, stops and resumes next frame, but since there is nothing left to do, it exits on the next frame.

A typical way to use coroutines is to have the yield return null in a while loop, so when it resumes, it continues the loop. Here is an example that do it

private IEnumerator MyRoutine()
{
    while(running) //running is a member bool that you could set to false to exit
    {
        // Do all the stuff you want to do in ONE frame
        // ...
        yield return null;
    }
}

Typically, the StartCoroutine would be called in the Start() function, or later when an event is triggered.

If you want to know more about coroutine, or check that you understood them properly, check out this page: https://docs.unity3d.com/Manual/Coroutines.html

or this video https://unity3d.com/learn/tutorials/topics/scripting/coroutines

// Edit: quickly present one useful option

In the snippet above, the while loop is very similar to the Update function (the inside of the loop is executed each frame). One nice option is to replace

yield return null

by

yield return new WaitForSeconds(waitTime)

where waitTime is a the time you want to wait before resuming, in seconds

// End of edit




回答2:


Do not use StartCoroutine() in the Update method. Call it in another method and use a while loop inside your coroutine function if needed. Just control your StartCoroutine() outside of Update method




回答3:


Update is called every frame, if your condition is ever true, you launch your coroutine every frame. Just set down your flag to only join 1 time.

void Update()
{
    if (startFinding)
    {
        startFinding = false;
        StartCoroutine(GameOptions());
    } 
}


来源:https://stackoverflow.com/questions/48199790/startcoroutine-is-being-called-so-many-times-c-unity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!