等待响应,然后继续执行主例程

时间:2019-09-18 05:03:33

标签: c# unity3d

我正在尝试制作一个简单的消息框,以帮助指导输出的可读性。我在Unity中使用C#。

之所以这样,是因为消息通常很长,令人费解或偶尔需要回复。

我正在尝试使用简单的DisplayMessage(string _message)标志调用bool方法,以使其关闭并继续。但是无论我做什么,它要么冻结(感谢while无限循环),要么传递到主线程

IEnumerable并不是我的强项之一,除非我错过了一些基本而明显的东西(我很愿意承认这种可能性),否则协程仍然不会坚持{{1} },直到我得到Button输入为止

我花了几个小时的时间,但我的目光一直盯着Systems.Threading解决方案中的选项

DoDisplay()

2 个答案:

答案 0 :(得分:2)

首先:您要在此处使用线程!使用它们进行繁重的操作,例如文件IO和序列化,是的,等等,但不只是等到应用程序中发生某些事情。唯一实现此目的的方法是必须额外注意将相应的回调传递回主线程等。

不需要例程/循环

如果仅是一次不需要任何连续更新或平稳移动的动作,那么如何在不使用bool标志和例程或循环的情况下使其基于事件全部

public void DoDisplay(string _displayMessage) 
{
    // Activate Panel
    DisplayPanel.SetActive(true);

    // display message
    Message_Text.text = _displayMessage;

    // log only once
    Debug.Log("Waiting");
}

// A simple Button press to clear the flag
public void OnComplete() 
{
    //Clear and close
    Message_Text.text = "";
    DisplayPanel.SetActive(false);
}

通常,无论如何,Debug.Log都应避免逐帧使用while,因为即使您在构建中不再看到控制台输出,它也会降低您的应用速度。


协程

自从您询问以来-替代方法可以使用CoroutineWaitWhileWaitUntil,或者如果您真的想再次使用简单的{{1} }。

请注意,协程仍在主线程中执行,因此此处的任何繁重操作仍可能冻结您的应用程序-例如,如果您未在其中yield return null进行闭环while;)< / p>

将它们视为临时yield return方法,因为实际上(使用默认的Update s)是在实际yield return方法之后逐帧执行。 还有一些例外,例如UpdateWaitForFixedUpdate,但也许到现在为止。

对于Unity的协程,WaitForEndOfFrame用非常简单的话表示,诸如“暂停该例程,继续执行主线程。稍后从您离开的地方继续该例程。”

yield return

我不知道您的主要代码在做什么,因为您没有添加它。您可以做的就是将其作为例行程序,例如

public void DoDisplay(string _displayMessage)
{
    // Be careful now with concurrent routines in case this gets called twice
    // You probably would want to stop the last routine and start a new one
    StopAllCoroutines();
    StartCoroutine(DoDisplayRoutine(_displayMessage));
}

public IEnumerator DoDisplayRoutine(string _displayMessage) 
{
    // Activate Panel
    DisplayPanel.SetActive(true);

    // Set flag and display message
    _isComplete = false;
    Message_Text.text = _displayMessage;

    Debug.Log("Waiting");
    yield return new WaitUntil(() => _isComplete);

    // OR if you really want to display the log every frame meanwhile
    while(!_isComplete)
    {
        Debug.Log("Waiting");
        // render this frame and continue from here in the next one
        // If you missed to yield return somewhere in a while loop
        // then yes, this would also freeze the main thread
        yield return null;
    }

    //Clear and close
    Message_Text.text = "";
    DisplayPanel.SetActive(false);
}

// A simple Button press to clear the flag
public void OnComplete() 
{
    _isComplete = true;
}

现在我们有了您的代码;)

如您所说,您可以这样做

IEnumerator YourMainCode()
{
    ... do something

    // show message and wait until it gets closed (using the later coroutine solution)
    yield return DoDisplayRoutine(_displayMessage);

    ... continue after message was closed
}

答案 1 :(得分:1)

情况

根据我的见解,您需要以下内容:

  • 在没有其他消息显示时在屏幕上显示消息
  • 如果显示其他消息,请先显示下一条

这不需要复杂的元素,例如线程,协程或其他任务管理器。这是Queue的工作。

您可以实现此算法:

算法

  1. 尝试显示一条消息
  2. 没有以前的消息=>确认显示消息
  3. 屏幕上的上一条消息=>使消息入队
  4. 完成时称为
  5. 队列中没有消息=>关闭菜单
  6. 队列中有消息=>显示下一条消息

消息队列

使用您的代码的实现如下。

public class DisplayManager : MonoBehaviour
{
    public GameObject DisplayPanel;

    public Text Message_Text;
    public Button Complete_Button;

    private Queue<string> _messages;

    public void DoDisplay(string displayMessage)
    {
        //if no messages are displayed, you display the message 
        if (string.IsNullOrEmpty(Message_Text.text)) ShowMessage(displayMessage);
        //if other messages are displayed you enqueue the message
        else _messages.Enqueue(displayMessage);
    }

    private void ShowMessage(string displayMessage)
    {
        // Activate Panel, if not already active
        if(!DisplayPanel.activeSelf) DisplayPanel.SetActive(true);

        // set the message on the text
        Message_Text.text = displayMessage;
    }

    // A simple Button press to clear the flag
    public void OnComplete()
    {
        //if we have other messages we show the next
        if (_messages.Count > 0) ShowMessage(_messages.Dequeue());
        //otherwise we close the menu
        else CloseMessage();
    }

    private void CloseMessage()
    {
        Message_Text.text = "";
        DisplayPanel.SetActive(false);
    }
}

进一步的逻辑

如果您想在消息显示器上添加更多的逻辑,则可以使用ShowMessage方法执行。

您可以在其中添加任何内容,例如

if(displayMessage == "Add Card") 
    //DO SOMETHING