如何在Unity中实现无需事件/委托回调的MessageBox功能
Unity 阻塞式MessageBox实现方案
Unity主线程负责所有UI渲染和交互事件响应,不能做真正的线程阻塞(会直接冻住整个程序,导致弹窗无法显示和点击),以下两种方案通过异步挂起实现逻辑上的等待效果,完全符合你要求的「拿到弹窗结果再执行后续代码」的需求。
方案1:async/await实现(最接近你给出的调用风格)
不需要引入第三方库,用C#原生Task即可实现,调用代码和你期望的写法几乎完全一致:
1. 定义返回值枚举
public enum DialogResult { None, Yes, No, Cancel }
2. MessageBox核心实现
using UnityEngine; using System.Threading.Tasks; public class MessageBox : MonoBehaviour { // Inspector面板赋值你的弹窗UI组件 [SerializeField] private UnityEngine.UI.Text messageText; [SerializeField] private UnityEngine.UI.Button yesButton; [SerializeField] private UnityEngine.UI.Button noButton; private static MessageBox _instance; private TaskCompletionSource<DialogResult> _resultSource; private void Awake() { _instance = this; gameObject.SetActive(false); // 绑定按钮点击事件 yesButton.onClick.AddListener(() => OnButtonClicked(DialogResult.Yes)); noButton.onClick.AddListener(() => OnButtonClicked(DialogResult.No)); } public static async Task<DialogResult> Show(string content) { // 显示弹窗,填充内容 _instance.gameObject.SetActive(true); _instance.messageText.text = content; // 初始化等待源 _instance._resultSource = new TaskCompletionSource<DialogResult>(); // 等待用户点击返回结果 return await _instance._resultSource.Task; } private void OnButtonClicked(DialogResult result) { // 隐藏弹窗,设置返回值结束等待 gameObject.SetActive(false); _resultSource.SetResult(result); } }
3. 调用示例
// 调用方法需要加async修饰 public async void ShowConfirmDialog() { DialogResult result = await MessageBox.Show("是否执行该操作?"); // 后续代码会自动等待用户点击按钮后才执行 if (result == DialogResult.Yes) { DoIt(); } else { DoNotDoIt(); } }
方案2:协程实现(兼容旧版本Unity)
如果你使用的Unity版本不支持async/await,可以用原生协程实现:
1. MessageBox核心实现
using UnityEngine; using System.Collections; public class MessageBox : MonoBehaviour { [SerializeField] private UnityEngine.UI.Text messageText; [SerializeField] private UnityEngine.UI.Button yesButton; [SerializeField] private UnityEngine.UI.Button noButton; private static MessageBox _instance; private DialogResult _currentResult; private bool _isWaitingForInput; private void Awake() { _instance = this; gameObject.SetActive(false); yesButton.onClick.AddListener(() => OnButtonClicked(DialogResult.Yes)); noButton.onClick.AddListener(() => OnButtonClicked(DialogResult.No)); } public static IEnumerator Show(string content, System.Action<DialogResult> onResult) { _instance.gameObject.SetActive(true); _instance.messageText.text = content; _instance._isWaitingForInput = true; // 每帧检测是否完成点击 while (_instance._isWaitingForInput) { yield return null; } // 返回结果执行后续逻辑 onResult?.Invoke(_instance._currentResult); } private void OnButtonClicked(DialogResult result) { gameObject.SetActive(false); _currentResult = result; _isWaitingForInput = false; } }
2. 调用示例
public void ShowConfirmDialog() { StartCoroutine(MessageBox.Show("是否执行该操作?", result => { if (result == DialogResult.Yes) { DoIt(); } else { DoNotDoIt(); } })); }
内容的提问来源于stack exchange,提问作者MrWatchmanLP
相关产品推荐
相关产品推荐

