diff --git a/DungeonShooting_Godot/src/framework/ui/UiBase.cs b/DungeonShooting_Godot/src/framework/ui/UiBase.cs
new file mode 100644
index 0000000..86a7934
--- /dev/null
+++ b/DungeonShooting_Godot/src/framework/ui/UiBase.cs
@@ -0,0 +1,50 @@
+
+using Godot;
+
+///
+/// Ui 基类
+///
+public abstract partial class UiBase : Control
+{
+ ///
+ /// 当前 UI 所属层级
+ ///
+ [Export]
+ public UiLayer Layer = UiLayer.Middle;
+
+ ///
+ /// Ui 模式
+ ///
+ [Export]
+ public UiMode Mode = UiMode.Normal;
+
+ ///
+ /// 阻止下层 Ui 点击
+ ///
+ [Export]
+ public bool KeepOut = false;
+
+ ///
+ /// 当前ui打开时调用,并接收参数
+ ///
+ public abstract void OnOpen(params object[] args);
+
+ ///
+ /// 当前ui关闭时调用
+ ///
+ public abstract void OnClose();
+
+ ///
+ /// 创建当前ui时调用
+ ///
+ public virtual void OnCreate()
+ {
+ }
+
+ ///
+ /// 销毁当前ui时调用
+ ///
+ public virtual void OnDispose()
+ {
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/ui/UiLayer.cs b/DungeonShooting_Godot/src/framework/ui/UiLayer.cs
new file mode 100644
index 0000000..4a7002e
--- /dev/null
+++ b/DungeonShooting_Godot/src/framework/ui/UiLayer.cs
@@ -0,0 +1,20 @@
+
+public enum UiLayer
+{
+ ///
+ /// 最底层
+ ///
+ Bottom,
+ ///
+ /// 中间层
+ ///
+ Middle,
+ ///
+ /// 较高层
+ ///
+ Height,
+ ///
+ /// 最顶层
+ ///
+ Pop,
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/ui/UiManager.cs b/DungeonShooting_Godot/src/framework/ui/UiManager.cs
new file mode 100644
index 0000000..289a729
--- /dev/null
+++ b/DungeonShooting_Godot/src/framework/ui/UiManager.cs
@@ -0,0 +1,27 @@
+
+using Godot;
+
+public static partial class UiManager
+{
+ private static bool _init = false;
+
+ public static void Init()
+ {
+ if (_init)
+ {
+ return;
+ }
+
+ _init = true;
+ }
+
+ public static UiBase OpenUi(string resourcePath)
+ {
+ return null;
+ }
+
+ public static T OpenUi(string resourcePath) where T : UiBase
+ {
+ return (T)OpenUi(resourcePath);
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/framework/ui/UiMode.cs b/DungeonShooting_Godot/src/framework/ui/UiMode.cs
new file mode 100644
index 0000000..d4d9ccb
--- /dev/null
+++ b/DungeonShooting_Godot/src/framework/ui/UiMode.cs
@@ -0,0 +1,12 @@
+
+public enum UiMode
+{
+ ///
+ /// 正常模式,可以开多个相同的 Ui
+ ///
+ Normal,
+ ///
+ /// 单例模式, 只能同时打开一个相同的 Ui
+ ///
+ Singleton,
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/game/GameApplication.cs b/DungeonShooting_Godot/src/game/GameApplication.cs
index 8dfea92..c7efa2e 100644
--- a/DungeonShooting_Godot/src/game/GameApplication.cs
+++ b/DungeonShooting_Godot/src/game/GameApplication.cs
@@ -81,6 +81,9 @@
ActivityObject.IsDebug = Debug;
//Engine.TimeScale = 0.3f;
+ //初始化ui
+ UiManager.Init();
+
GlobalNodeRoot = GetNode(GlobalNodeRootPath);
// 初始化鼠标
Input.MouseMode = Input.MouseModeEnum.Hidden;
diff --git a/DungeonShooting_Godot/src/test/TestUi/Test.cs b/DungeonShooting_Godot/src/test/TestUi/Test.cs
new file mode 100644
index 0000000..7f13fc1
--- /dev/null
+++ b/DungeonShooting_Godot/src/test/TestUi/Test.cs
@@ -0,0 +1,69 @@
+using Godot;
+
+namespace UI;
+
+
+/*
+ Test
+ c1
+ c11
+ c2
+ */
+public abstract partial class Test : UiBase
+{
+ public UiNode2_c1 c1 { get; private set; }
+ public UiNode3_c2 c2 { get; private set; }
+
+ public class UiNode1_c11
+ {
+ public Control Instance { get; private set; }
+
+ public UiNode1_c11(Control node)
+ {
+ Instance = node;
+ }
+
+ public UiNode1_c11 Clone()
+ {
+ return new UiNode1_c11((Control)Instance.Duplicate());
+ }
+ }
+
+ public class UiNode2_c1
+ {
+ public Control Instance { get; private set; }
+ public UiNode1_c11 c11 { get; private set; }
+
+ public UiNode2_c1(Control node)
+ {
+ Instance = node;
+ c11 = new UiNode1_c11(node.GetNode("c11"));
+ }
+
+ public UiNode2_c1 Clone()
+ {
+ return new UiNode2_c1((Control)Instance.Duplicate());
+ }
+ }
+
+ public class UiNode3_c2
+ {
+ public Control Instance { get; private set; }
+
+ public UiNode3_c2(Control node)
+ {
+ Instance = node;
+ }
+
+ public UiNode3_c2 Clone()
+ {
+ return new UiNode3_c2((Control)Instance.Duplicate());
+ }
+ }
+
+ public sealed override void _Ready()
+ {
+ c1 = new UiNode2_c1(GetNode("c1"));
+ c2 = new UiNode3_c2(GetNode("c2"));
+ }
+}
\ No newline at end of file
diff --git a/DungeonShooting_Godot/src/test/TestUi/TestPanel.cs b/DungeonShooting_Godot/src/test/TestUi/TestPanel.cs
new file mode 100644
index 0000000..0388b86
--- /dev/null
+++ b/DungeonShooting_Godot/src/test/TestUi/TestPanel.cs
@@ -0,0 +1,15 @@
+namespace UI;
+
+public class TestPanel : Test
+{
+
+ public override void OnOpen(params object[] args)
+ {
+
+ }
+
+ public override void OnClose()
+ {
+
+ }
+}
\ No newline at end of file