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

Unity实现等待用户输入的同步式消息框方法

在Unity中实现类似WinForms的同步阻塞式自定义消息框

核心逻辑

Unity的主线程不能直接硬阻塞(否则游戏会彻底卡死),所以咱们用**协程(Coroutine)**来模拟WinForms里MessageBox.Show()的同步等待效果——通过监听弹窗的关闭事件,让后续代码必须等当前弹窗关掉之后才继续执行。

具体实现步骤

1. 搭建弹窗UI与基础脚本

先做一个弹窗GameObject(做成预制体方便复用),包含可点击关闭的背景、文本显示区、关闭按钮,然后给它挂载CustomMessageBox.cs脚本:

using UnityEngine;
using UnityEngine.UI;
using System;

public class CustomMessageBox : MonoBehaviour
{
    public Text messageText;
    public Button closeButton;
    public RectTransform backgroundPanel;

    private Action _onCloseCallback;

    private void Awake()
    {
        // 绑定按钮关闭事件
        closeButton.onClick.AddListener(CloseMessageBox);
        // 给背景面板添加点击关闭逻辑(可选)
        var bgButton = backgroundPanel.GetComponent<Button>();
        if (bgButton != null)
        {
            bgButton.onClick.AddListener(CloseMessageBox);
        }
        // 默认隐藏弹窗
        gameObject.SetActive(false);
    }

    // 对外暴露的显示方法,传入消息内容和关闭后的回调
    public void Show(string message, Action onClose = null)
    {
        messageText.text = message;
        _onCloseCallback = onClose;
        gameObject.SetActive(true);
    }

    private void CloseMessageBox()
    {
        gameObject.SetActive(false);
        _onCloseCallback?.Invoke();
    }
}

2. 用协程实现顺序弹窗

在需要触发弹窗的脚本里,通过协程串联多个弹窗,确保前一个关闭后才执行后续逻辑:

using UnityEngine;
using System.Collections;

public class MessageSequenceDemo : MonoBehaviour
{
    public CustomMessageBox messageBoxPrefab;

    private void Start()
    {
        // 启动协程执行顺序弹窗逻辑
        StartCoroutine(ShowMessagesInOrder());
    }

    private IEnumerator ShowMessagesInOrder()
    {
        // 第一个弹窗,等待关闭后再执行后续代码
        yield return WaitForMessageBox("第一个弹窗,关闭后显示下一个");
        
        Debug.Log("第一个弹窗已关闭");
        // 第二个弹窗
        yield return WaitForMessageBox("这是第二个弹窗");
        
        // 所有弹窗关闭后,执行后续业务逻辑
        Debug.Log("全部弹窗处理完成");
    }

    // 封装等待弹窗关闭的协程方法
    private IEnumerator WaitForMessageBox(string message)
    {
        // 实例化弹窗(基于预制体)
        var messageBox = Instantiate(messageBoxPrefab, transform);
        bool isClosed = false;
        
        messageBox.Show(message, () => 
        {
            isClosed = true;
            Destroy(messageBox.gameObject); // 用完销毁,也可以用对象池回收优化
        });

        // 每一帧检查弹窗是否关闭,未关闭则继续等待
        while (!isClosed)
        {
            yield return null;
        }
    }
}

3. 进阶优化:单例弹窗复用

如果不想频繁实例化销毁弹窗,可以把弹窗做成单例,全局复用同一个对象:

修改CustomMessageBox.cs添加单例逻辑:

public class CustomMessageBox : MonoBehaviour
{
    public static CustomMessageBox Instance { get; private set; }

    private void Awake()
    {
        // 单例逻辑,确保全局只有一个弹窗实例
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject); // 跨场景保留弹窗
        }
        else
        {
            Destroy(gameObject);
        }
        
        // 原有Awake中的事件绑定逻辑...
    }

    // 对外提供静态调用方法,简化使用
    public static void Show(string message, Action onClose = null)
    {
        Instance.Show(message, onClose);
    }
}

之后修改协程中的调用代码:

private IEnumerator WaitForMessageBox(string message)
{
    bool isClosed = false;
    CustomMessageBox.Show(message, () => isClosed = true);

    while (!isClosed)
    {
        yield return null;
    }
}

重点提醒

  • 绝对不能用Thread.Sleep()这类硬阻塞主线程的方法,Unity的渲染与逻辑都依赖主线程,硬阻塞会导致游戏彻底失去响应。
  • 协程的本质是在每一帧间隙检查条件,不会阻塞游戏运行,完美模拟出同步等待的体验。
  • 如果需要实现带确认/取消的弹窗,只需扩展CustomMessageBox的按钮与回调逻辑,比如把Action换成Action<bool>来区分用户操作。

内容的提问来源于stack exchange,提问作者Honey22Sharp

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:01:16