【问题标题】:Unity UI text appears properly in game view, but not in buildUnity UI 文本在游戏视图中正确显示,但在构建中不显示
【发布时间】:2020-06-05 09:54:21
【问题描述】:

我正在通过 UDP 连接接收数据,我已将其显示为 UI 文本。现在这在游戏视图中运行良好,而当我构建并运行它时,文本显示但不显示值。我在下面附上了图片。

Game view - Build view

我是这样设置的:

[SerializeField]
Text testing;

public string text2 = "";

然后我在这个函数中引用了 UI 文本对象:

public void OnGUI()
{
    //other stuff for this function

    testing = GetComponent<Text>();
    testing.text = "altitude:" + text2;
}

在接收数据函数中,我定义了我想要的文本:

    void ReceiveData()
{

    client = new UdpClient(port);
    while (true)
    {
        try
        {
            // Bytes received.
            IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
            byte[] data = new byte[1024];
            data = client.Receive(ref anyIP);
            var dest = data.Skip(21).Take(4).ToArray();

            //converting bytes to string
            float value = BitConverter.ToSingle(dest, 0);
            string text = value.ToString();
            text2 = text;
            // print text
            print(">> " + text)
        }
        catch (Exception err)
        {
            print(err.ToString());
        }
    }
}

【问题讨论】:

    标签: c# unity3d user-interface


    【解决方案1】:

    一般来说:您应该使用OnGUI!它是一种遗留物,并且已经被您已经在使用的 UI 系统所取代。

    如果您希望每帧都发生一些事情,请使用Update


    我假设(希望)UdP 在后台线程中运行。我会使用一种通常称为“主线程调度程序”的模式:

    • 有一个ConcurrentQueueConcurrentStack(取决于您的需要),它们是线程保存
    • 从任何线程通过Enqueue(queue) 或Push(stack) 向其添加新项目
    • 在Unity主线程中有一个worker使用TryDequeue(queue)接收并移除第一项,或者TryPop(stack)接收并移除最后一项

      -> 在主线程中执行


    您可以使用ConcurrentQueue(先进先出)

    private readonly ConcurrentQueue<Action> actions = new ConcurrentQueue<Action>();
    
    private void Update()
    {
        while(actions.TryDequeue(out var Action)
        {
            action?.Invoke();
        }
    }
    

    在这种情况下,您希望处理自上一帧以来附加到队列的所有操作。您可以从您的 UDP 线程中添加相应的操作,例如

        ...
    
        float value = BitConverter.ToSingle(dest, 0);
        string text = value.ToString();
    
        actions.Enqueue(() => 
        {
            text2 = text;
            // print text
            print(">> " + text);
        }
    }
    catch(Exception err
    {
        actions.Enqueue(() => print(err.ToString());
    }
    

    或者在您的情况下,您甚至可以对其进行一些优化并节省一些工作/资源:仅使用并显示 last 接收到的字符串,以便您可以使用ConcurrentStack(last-in first -出)

    private readonly ConcurrentStack<string> receivedStrings = new ConcurrentStack<string>();
    
    private void Update()
    {
        if(receivedStrings.TryPop(out var message))
        {
            text2 = message;
            print(">> " + message);
    
            // dump all previous messages
            receivedStrings.Clear();
        }
    }
    

    然后您只需将收到的消息添加到堆栈中,例如

    ...
    
     float value = BitConverter.ToSingle(dest, 0);
     string text = value.ToString();
    
     receivedStrings.Push(text);
    

    至于您对多个文本组件的评论:

    是的,您可以使用多个ConcurrentStack。然后我会像这样使用它们:

    // First define the IDs you want to use
    private enum StackID
    {
        Text1,
        Text2,
        Text3,
        ...
    }
    
    // Reference your individual Text components via the Inspector
    [SerializeField] private Text _text1;
    [SerializeField] private Text _text2;
    [SerializeField] private Text _text3;
    ...
    
    // The special string you use for splitting the receivedessage
    // configure via the Inspector
    [SerializeField] private string _splitter = "$$";
    
    // This holds all ConcurrentStack addressed by their StackID
    private Dictionary<StackID, ConcurrentStack<string>> _stacks = new Dictionary<StackID, ConcurrentStack<string>>();
    
    // This links the given Text components to a certain StackID
    // in other words which text shall listen to which stack
    private Dictionary<StackID, Text> _texts = new Dictionary<StackID, Text>();
    
    private void Awake ()
    {
        // Initialize the dictionaries
        foreach(var id in (StackID[])Enum.GetValues(typeof(StackID)))
        {
            _stacks.Add(id, new ConcurrentStack<string>());
        }
    
        _texts.Add(StackID.Text1, _text1);
        _texts.Add(StackID.Text2, _text2);
        _texts.Add(StackID.Text3, _text3);
        ...
    }
    
    private void Start ()
    {
        // start the Receiver
        var thread = new Thread(new ThreadStart(ReceiveData));
        thread.Start();
    }
    
    private void Update ()
    {
        // Iterate through all values of StackID
        foreach(var id in (StackID[])Enum.GetValues(typeof(StackID)))
        {
            if(_stacks[id].TryPop(out var message))
            {
                _texts[id].text = message;
                print(">> " + message);
    
                // dump all previous messages
                _stacks[id].Clear();
            }
        }
    }
    
    // On Background Thread
    void ReceiveData()
    {
        client = new UdpClient(port);
        while (true)
        {
            try
            {
                // Bytes received.
                IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
                byte[] data = new byte[1024];
                data = client.Receive(ref anyIP);
    
                //converting bytes to string
                var message = Encoding.UTF8.GetString(data);
    
                // Now split the message into your parts and pass them into the individual stacks
                var texts = message.Split(new string[]{ _splitter }, message);
    
                _stacks[StackID.Text1]. Enqueue(texts[0]);
                _stacks[StackID.Text2]. Enqueue(texts[1]);
                _stacks[StackID.Text3]. Enqueue(texts[2]);
                ...
            }
            catch (Exception err)
            {
                foreach(var id in (StackID[])Enum.GetValues(typeof(StackID)))
                {
                    _stacks[id].Enqueue(err.ToString());
                }
            }
        }
    }
    

    注意:在智能手机上打字,所以没有保修,但我希望这个想法能清楚

    【讨论】:

    • 感谢您的回答。我一直在使用 ConcurrentStack 方法,它可以工作,但为了将来参考,如果我想使用多个字符串,使用多个 ConcurrentStack 是否是个好主意?因此,在示例中有 text2,然后您可以将 text3 和 text4 推送到其他堆栈(receivedStrings3 和 receivedStrings4)。
    • @Dully737 这始终取决于您的用例。一般来说,我会为每个 udp/tcp 接收器设置一个堆栈。但是,如果您还需要string.Split 收到的消息,我会按照您的描述在后台线程上进行拆分,并使用多个ConcurrentStack foreach 文本组件。没有什么不好的。为了在代码中保持干净,我可能会使用Dictionary&lt;someEnum, ConcurrentStack&lt;string&gt;&gt; 所以这个字典包含对所有堆栈的引用,你所要做的就是将 id 条目添加到枚举
    • 见底部的更新。我只是在打电话,所以我没有测试它,但我认为这应该可以工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    相关资源
    最近更新 更多