我正在尝试制作一个简单的消息框,以帮助指导输出的可读性。我在Unity中使用C#。
之所以这样,是因为消息通常很长,令人费解或偶尔需要回复。
我正在尝试使用简单的DisplayMessage(string _message)
标志调用bool
方法,以使其关闭并继续。但是无论我做什么,它要么冻结(感谢while
无限循环),要么传递到主线程
IEnumerable
并不是我的强项之一,除非我错过了一些基本而明显的东西(我很愿意承认这种可能性),否则协程仍然不会坚持{{1} },直到我得到Button输入为止
我花了几个小时的时间,但我的目光一直盯着Systems.Threading解决方案中的选项
DoDisplay()
答案 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
,因为即使您在构建中不再看到控制台输出,它也会降低您的应用速度。
自从您询问以来-替代方法可以使用Coroutine和WaitWhile
或WaitUntil
,或者如果您真的想再次使用简单的{{1} }。
请注意,协程仍在主线程中执行,因此此处的任何繁重操作仍可能冻结您的应用程序-例如,如果您未在其中yield return null
进行闭环while
;)< / p>
将它们视为临时yield return
方法,因为实际上(使用默认的Update
s)是在实际yield return
方法之后逐帧执行。 还有一些例外,例如Update
或WaitForFixedUpdate
,但也许到现在为止。
对于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
的工作。
您可以实现此算法:
使用您的代码的实现如下。
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