Godot UI執行緒,Task非同步和訊息彈窗通知

gclove2000發表於2024-04-12

目錄
  • 前言
  • 執行緒安全
  • 全域性訊息IOC注入
  • 訊息視窗搭建
    • 最簡單的訊息提示
      • 簡單使用
    • 仿Element UI
      • ElementUI 效果
      • 簡單的Label樣式
      • 如何快速載入多個相同節點
      • 修改一下,IOC按鈕事件註冊
  • 總結

前言

最近我在研究Godot的全域性訊息,然後發現Godot 也是有UI執行緒限制的,只能在主執行緒的子執行緒裡面修改UI。

執行緒安全

全域性訊息IOC注入

我之前寫過Godot 的IOC注入,這些都是CSDN時期的部落格。但是後面CSDN的廣告實在是太多了,我就轉到部落格園裡面來了。

Godot 學習筆記(5):徹底的專案工程化,解決GodotProjectDir is null+工程化範例

Godot.NET C# 工程化開發(1):通用Nuget 匯入+ 模板檔案匯出,包含隨機數生成,日誌管理,資料庫連線等功能

注意,我後面的都是基於我那個IOC框架來寫的。

訊息視窗搭建

如何修改Label樣式可以看我上一篇文章

Godot Label樣式 Textrue紋理,實現樣式修改,背景填充

最簡單的訊息提示

using Godot;
using Godot_UI_Test.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace Godot_UI_Test.SceneModels
{
    public class MessageSceneModel : ISceneModel
    {
        private PrintHelper printHelper;

        private Godot.Label title;

        private Godot.Label content;

        private VBoxContainer container;

        private ColorRect colorRect;

        


        public MessageSceneModel(PrintHelper printHelper) {
            this.printHelper = printHelper;
            printHelper.SetTitle(nameof(MessageSceneModel));
        }
        public override void Process(double delta)
        {
            //throw new NotImplementedException();
        }

        public override void Ready()
        {
            printHelper.Debug("載入完成");
            colorRect = Scene.GetNode<ColorRect>("ColorRect");

            container = colorRect.GetNode<VBoxContainer>("VBoxContainer");
            title = container.GetNode<Godot.Label>("Title");
            content = container.GetNode<Godot.Label>("Content");
            //同步容器大小
            container.Size = colorRect.Size;
            printHelper.Debug(JsonConvert.SerializeObject(title.Size));

            //預設設定為不可見
            Scene.Visible = false;
            //throw new NotImplementedException();
        }


        /// <summary>
        /// 彈窗延遲退出
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task ShowInfo(string message)
        {
            Scene.Visible = true;
            printHelper.Debug("Info列印資訊");
            printHelper.Debug(message);
            await Task.Delay(3000);
            Scene.Visible = false;

        }
    }
}

簡單使用

雖然有點醜,但是能用

仿Element UI

ElementUI 效果

簡單的Label樣式

簡單的畫一下,我就不給具體的引數了,大家點一下就知道了

如何快速載入多個相同節點

如果我們把這個作為場景,又沒有那麼的複雜。如果用程式碼生成,寫起來很麻煩,也不直觀。最好的方法就是複製節點新增。

using Godot;
using Godot_UI_Test.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace Godot_UI_Test.SceneModels
{
    public class MessageSceneModel : ISceneModel
    {
        private PrintHelper printHelper;

        private VBoxContainer vBoxContainer;

        private AssetsHelper assetsHelper;

        private Godot.Label label;


        public MessageSceneModel(PrintHelper printHelper, AssetsHelper assetsHelper)
        {
            this.printHelper = printHelper;
            printHelper.SetTitle(nameof(MessageSceneModel));
            this.assetsHelper = assetsHelper;
        }
        public override void Process(double delta)
        {
            //throw new NotImplementedException();
        }

        public override void Ready()
        {
            printHelper.Debug("載入完成");
            vBoxContainer = Scene.GetNode<VBoxContainer>("VBoxContainer");
            label = Scene.GetNode<Godot.Label>("Label");

            //將vBoxContainer居中,GodotProjectSetting是自己設定的
            vBoxContainer.Position = new Vector2(GodotProjectSetting.Width/4, 10);


            //新增label的靠別,不能直接新增label,因為label已經擁有了父節點
            var newLabel = label.Duplicate() as Godot.Label;
            //顯示Label
            newLabel.Visible =true;
            vBoxContainer.AddChild(newLabel.Duplicate());
            vBoxContainer.AddChild(newLabel.Duplicate());
            vBoxContainer.AddChild(newLabel.Duplicate());
            //CreateText("te321");

            //CreateText("te321 3213 321 3434 4 2 41321 st1 te321 3213 321 3434 4 2 41321 st1 te321 3213 321 3434 4 2 41321 st1");

            printHelper.Debug(JsonConvert.SerializeObject(vBoxContainer.Position));
            printHelper.Debug(JsonConvert.SerializeObject(vBoxContainer.GetWindow().Position));
            //Scene.Visible = false;
            //throw new NotImplementedException();
        }

        private void CreateText(string text)
        {
            var res = new Godot.Label();
            res.AddThemeStyleboxOverride("normal", assetsHelper.MessageItemStyle);
            res.AutowrapMode = TextServer.AutowrapMode.WordSmart;
            res.HorizontalAlignment = HorizontalAlignment.Center;
            res.Text = text;
            res.CustomMinimumSize = new Vector2(200, 0);
            label = res;
            vBoxContainer.AddChild(res);
        }


        /// <summary>
        /// 延遲列印
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task ShowInfo(string message)
        {
            printHelper.Debug("Info列印資訊");

        }
    }
}

修改一下,IOC按鈕事件註冊

using Godot;
using Godot_UI_Test.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

namespace Godot_UI_Test.SceneModels
{
    public class MessageSceneModel : ISceneModel
    {
        private PrintHelper printHelper;

        private VBoxContainer vBoxContainer;

        private AssetsHelper assetsHelper;

        private Godot.Label label;


        public MessageSceneModel(PrintHelper printHelper, AssetsHelper assetsHelper)
        {
            this.printHelper = printHelper;
            printHelper.SetTitle(nameof(MessageSceneModel));
            this.assetsHelper = assetsHelper;
        }
        public override void Process(double delta)
        {
            //throw new NotImplementedException();
        }

        public override void Ready()
        {
            printHelper.Debug("載入完成");
            vBoxContainer = Scene.GetNode<VBoxContainer>("VBoxContainer");
            label = Scene.GetNode<Godot.Label>("Label");

            //將vBoxContainer居中,GodotProjectSetting是自己設定的
            vBoxContainer.Position = new Vector2(GodotProjectSetting.Width/4, 10);



            //CreateText("te321 3213 321 3434 4 2 41321 st1 te321 3213 321 3434 4 2 41321 st1 te321 3213 321 3434 4 2 41321 st1");

            printHelper.Debug(JsonConvert.SerializeObject(vBoxContainer.Position));
            printHelper.Debug(JsonConvert.SerializeObject(vBoxContainer.GetWindow().Position));
            //Scene.Visible = false;
            //throw new NotImplementedException();
        }

        /// <summary>
        /// 掛載Label
        /// </summary>
        /// <param name="text"></param>
        private Godot.Label CreateText(string text)
        {
            var newLabel = label.Duplicate() as Godot.Label;
            newLabel.Text = text;
            newLabel.Visible=true;
            vBoxContainer.AddChild(newLabel);
            return newLabel;
        }


        /// <summary>
        /// 延遲列印
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task ShowInfo(string message)
        {
            printHelper.Debug("Info列印資訊");

            var newLabel =  CreateText(message);
            await Task.Delay(3 * 1000);
            newLabel.Free();

        }
    }
}

總結

我只是很潦草的實現了訊息彈窗這個功能,還沒加動畫效果。不過這個確實讓我學到了很多,尤其是節點掛載這個事情。

相關文章