Start例程被调用了很多次(C#Unity)

Start例程被调用了很多次(C#Unity),c#,arrays,unity3d,coroutine,C#,Arrays,Unity3d,Coroutine,我正在Unity中创建一个弹出菜单选项。现在我的问题是,我在void update中创建的协同程序被调用了很多次。我的意思是,在我的Unity控制台上,Debug.log正在增加。它不应该是正确的,因为它已经协同工作了。可以帮助我了解更多的合作项目,帮助我解决我的小问题吗 这是我的密码: [SerializeField] GameObject Option; [SerializeField] Button btn,btn2; [SerializeField] GameObject open, c

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

这是我的密码:

[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);
}
[序列化字段]
游戏对象选项;
[序列化字段]
按钮btn,btn2;
[序列化字段]
游戏对象打开,关闭;
[序列化字段]
游戏对象[]选择;
bool startFinding=false;
void Start()
{
Option.SetActive(false);
按钮弹出=btn.GetComponent();
按钮popUp2=btn2.GetComponent();
popUp.onClick.AddListener(PopUpOption);
popUp2.onClick.AddListener(ClosePopUp);
}
无效更新()
{
如果(开始查找)
{
start例程(GameOptions());
} 
}
IEnumerator游戏选项()
{
//拿到所有的标签
opt=GameObject.FindGameObjectsWithTag(“MobileOptions”);
if(opt[0].GetComponent().isOn==true&&opt[1].GetComponent().isOn==true)
{
Log(“首先禁用该复选框,然后在“+”'rendering'+”和“+”'livestreaming'”之间仅选择1个选项);
}
//直播
if(opt[0].GetComponent().isOn==true)
{
Log(“Livestreaming激活”);
}否则
{
Log(“Livestreaming停用”);
}
//渲染
if(opt[1].GetComponent().isOn==true)
{
Log(“渲染激活”);
}否则
{
Debug.Log(“呈现停用”);
}
//雾
if(opt[2].GetComponent().isOn==true)
{
调试日志(“雾激活”);
}否则
{
Debug.Log(“雾停用”);
}
//摄影机效果
if(opt[3].GetComponent().isOn==true)
{
调试日志(“相机效果激活”);
}否则{
Debug.Log(“相机效果停用”);
}
收益返回空;
}
void PopUpOption()
{
startFinding=true;
//禁用移动选项按钮
open.SetActive(false);
//启用关闭选项按钮
close.SetActive(true);
//激活移动选项
Option.SetActive(true);
}
void ClosePopUp()
{
开始查找=错误;
//单击“移动选项”按钮
open.SetActive(true);
//禁用关闭选项按钮
close.SetActive(false);
//停用移动选项
Option.SetActive(false);
}

不要在
更新方法中使用
启动例程()
。在另一个方法中调用它,如果需要,在
coroutine
函数中使用
while循环
。只需在
Update
方法之外控制您的
start例程()
,不要在
Update
方法中使用
start例程()
。在另一个方法中调用它,如果需要,在
coroutine
函数中使用
while循环
。只要控制
start例程()
之外的
Update
方法

每帧调用一次更新,如果您的条件为真,则每帧启动一次协同例程。 只要放下你的旗帜,只加入一次

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

更新在每一帧调用,如果您的条件为真,则在每一帧启动您的协同路由。 只要放下你的旗帜,只加入一次

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

以下是协同程序的工作原理:

假设我有一个名为MyRoutine的couroutine函数(在您的例子中,您称之为GameOptions)

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

StartCoroutine(MyRoutine));
只需像任何常用方法一样调用
MyRoutine
。因此,如果在update中调用它,它将一直被调用,就像任何方法一样。这不是你想要的。协同程序的特殊之处在于,您可以在其中使用
yield
关键字。有很多方法可以使用它,但最常用(也是最简单)的一种方法是执行
并返回null

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

为了回到你在问题中发布的内容,你在最后写了
yield return null
。因此,您的方法正在执行,就在最后,停止并继续下一帧,但由于没有什么要做的,它将在下一帧退出

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

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;
    }
}
通常情况下,在Start()函数中或稍后触发事件时会调用Start例程

如果您想了解有关协同程序的更多信息,或者检查您是否正确理解它们,请查看此页面:

还是这个视频

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

在上面的代码段中,while循环与Update函数非常相似(循环的内部在每一帧执行)。一个很好的选择是替换

yield return null

其中,
waitTime
是恢复前要等待的时间,以秒为单位


//编辑结束

以下是协同程序的工作方式:

假设我有一个名为MyRoutine的couroutine函数(在您的例子中,您称之为GameOptions)

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

StartCoroutine(MyRoutine));
只需像任何常用方法一样调用
MyRoutine
。因此,如果在update中调用它,它将一直被调用,就像任何方法一样。这不是你想要的。协同程序的特殊之处在于,您可以在其中使用
yield
关键字。有很多方法可以使用它,但最常用(也是最简单)的一种方法是执行
并返回null

yield return null
表示“停止此协同程序,但在下一帧继续执行”。
您不需要