using GFramework.Game.Abstractions.enums; using GFramework.Game.Abstractions.ui; using Godot; namespace GFramework.Godot.ui; /// /// Godot平台的UI根节点实现 /// 用于管理UI页面的添加、移除和层级排序 /// public partial class GodotUiRoot(IReadOnlyDictionary? layerZOrderMap) : Node, IUiRoot { /// /// UI层级与Z轴顺序的映射表,定义了不同UI层的渲染优先级 /// /// /// 默认层级映射关系: /// - Page: 0 (基础页面层) /// - Overlay: 100 (覆盖层) /// - Modal: 200 (模态窗口层) /// - Toast: 300 (提示消息层) /// - Topmost: 400 (最顶层) /// private readonly IReadOnlyDictionary _layerZOrderMap = layerZOrderMap ?? new Dictionary { { UiLayer.Page, 0 }, { UiLayer.Overlay, 100 }, { UiLayer.Modal, 200 }, { UiLayer.Toast, 300 }, { UiLayer.Topmost, 400 } }; /// /// UI页面的追踪字典,记录每个页面的节点 /// private readonly Dictionary _pageNodes = new(); /// /// UI节点的父容器,所有UI页面都添加到这个节点下 /// private Node? _uiContainer; /// /// 向UI根节点添加子页面 /// public void AddUiPage(IUiPageBehavior child) { if (_uiContainer == null) throw new InvalidOperationException("UiContainer is not initialized"); var node = GetNodeFromPage(child); if (node == null) throw new InvalidOperationException($"Page node is null: {child.Key}"); if (!_pageNodes.TryAdd(child, node)) return; if (node.GetParent() != _uiContainer) _uiContainer.AddChild(node); } /// /// 向UI根节点添加子页面到指定层级 /// public void AddUiPage( IUiPageBehavior child, UiLayer layer, int orderInLayer = 0) { AddUiPage(child); var z = GetBaseZOrder(layer) + orderInLayer; SetZOrder(child, z); } /// /// 从UI根节点移除子页面 /// public void RemoveUiPage(IUiPageBehavior child) { if (!_pageNodes.Remove(child, out var node)) return; if (_uiContainer != null && node.GetParent() == _uiContainer) _uiContainer.RemoveChild(node); } /// /// 设置页面的Z-order(层级顺序) /// public void SetZOrder(IUiPageBehavior page, int zOrder) { if (!_pageNodes.TryGetValue(page, out var node)) return; if (node is CanvasItem canvasItem) canvasItem.ZIndex = zOrder; } /// /// 获取当前所有显示的页面 /// public IReadOnlyList GetVisiblePages() { return _pageNodes.Keys.ToList().AsReadOnly(); } public override void _Ready() { // 创建UI容器节点 _uiContainer = new Node { Name = "UiContainer" }; AddChild(_uiContainer); } /// /// 从页面行为获取对应的节点 /// private static Node? GetNodeFromPage(IUiPageBehavior page) { return page.View as Node; } private int GetBaseZOrder(UiLayer layer) { return !_layerZOrderMap.TryGetValue(layer, out var z) ? throw new ArgumentOutOfRangeException(nameof(layer), layer, null) : z; } }