【问题标题】:StartCoroutine is being called so many times (C# Unity)StartCoroutine 被多次调用(C# Unity)
【发布时间】:2018-06-20 08:28:57
【问题描述】:

我正在 Unity 中创建一个弹出菜单选项。现在我的问题是我在 void update 中制作的协程被调用了很多次。我的意思是在我的 Unity 控制台上,Debug.Logs 正在递增。它不应该是正确的,因为它已经是协程的。可以帮助我了解更多协程并帮助我解决我的小问题。

这是我的代码:

[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);
}

【问题讨论】:

  • 据我所知,代码完全按照您的要求执行。当然,Update() 方法会被重复调用。在该方法中,只要将startFinding 字段设置为true,就可以启动协同程序。因此,一旦显示弹出窗口,我绝对希望您的协同程序会启动多次(通常,Update() 方法每秒调用数十次)。如果您不希望它继续启动,那么...不要继续启动它!
  • 说了这么多,不清楚你为什么首先把它作为一个协程......它有一个直通的执行路径,没有任何类型的循环,通常会在一个协同程序。
  • 哦,你是说先生这是正常的,因为它在我的更新功能上??
  • “这很正常,因为它在我的更新功能上?” -- 是的,“正常”,因为这正是你编写的代码要做的事情.我不知道你打算做什么,所以我不能说这是否正确(你的问题表明它不是),但不知道你为什么选择编写协程首先,以及您期望它如何工作,不可能提出一个可以解决您的问题的实际答案。
  • “你的意思是它有一个直通的执行路径,没有任何通常会在协同程序中找到的循环”——有没有循环语句,例如whileforforeach 等。在 Unityd3 中,协程从被调用到第一个 yield return 执行,此时控制权返回给调用者。然后控制在调用者(在枚举器上调用MoveNext(),但这在这里并不重要)的控制下恢复,紧跟yield return。您的方法只产生一次,然后就完成了。非典型的协同程序。

标签: c# arrays unity3d coroutine


【解决方案1】:

不要在Update 方法中使用StartCoroutine()。如果需要,请以另一种方法调用它并在 coroutine 函数中使用 while loop。只需在Update 方法之外控制您的StartCoroutine()

【讨论】:

  • 这并不能真正帮助 OP。它会阻止它重复启动,但由于该方法并不是一个真正有用的协同例程,因此没有证据表明在 Update() 方法之外调用它一次实际上会实现 OP 想要的。跨度>
【解决方案2】:

每帧都会调用更新,如果您的条件为真,则每帧都会启动您的协程。 只需放下您的旗帜,仅加入 1 次即可。

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

【讨论】:

    【解决方案3】:

    协程的工作原理如下:

    假设我有一个名为 MyRoutine 的协同程序函数(在你的例子中,你称之为 GameOptions)

    private IEnumerator MyRoutine()
    

    然后,在我的代码中的任何地方,调用

    StartCoroutine(MyRoutine));
    

    将像任何常用方法一样简单地调用MyRoutine。因此,如果您在更新中调用它,它将一直被调用,就像任何方法一样。这不是你想要的。协程的特别之处在于您可以在其中使用 yield 关键字。有很多方法可以使用它,但最常用(也是最简单)的一种是 yield return null

    yield return null 表示“停止此协程,但在下一帧继续执行”。您不需要调用任何其他函数(当然不是 StartCoroutine)。执行将在下一帧继续。

    要回到您在问题中发布的内容,您在最后写了yield return null。所以你的方法正在执行,并在最后停止并恢复下一帧,但由于没有什么可做的,它在下一帧退出。

    使用协程的典型方法是将yield return null 放在一个while 循环中,这样当它恢复时,它会继续循环。这是一个例子

    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;
        }
    }
    

    通常,StartCoroutine 将在 Start() 函数中调用,或者稍后在触发事件时调用。

    如果您想了解更多关于协程的信息,或者检查您是否正确理解了它们,请查看此页面:https://docs.unity3d.com/Manual/Coroutines.html

    或此视频https://unity3d.com/learn/tutorials/topics/scripting/coroutines

    // 编辑:快速呈现一个有用的选项

    在上面的sn-p中,while循环与Update函数非常相似(循环内部是每帧执行一次)。一个不错的选择是替换

    yield return null
    

    yield return new WaitForSeconds(waitTime)
    

    其中waitTime 是您希望在恢复之前等待的时间,以秒为单位

    // 编辑结束

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      • 1970-01-01
      • 2016-08-19
      • 2018-02-09
      • 2017-03-24
      • 2021-05-01
      • 1970-01-01
      相关资源
      最近更新 更多