You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 07:06:07