diff --git a/DungeonShooting_Godot/src/framework/ui/IUiNode.cs b/DungeonShooting_Godot/src/framework/ui/IUiNode.cs index 12f5c8f..5e56ca1 100644 --- a/DungeonShooting_Godot/src/framework/ui/IUiNode.cs +++ b/DungeonShooting_Godot/src/framework/ui/IUiNode.cs @@ -9,25 +9,25 @@ /// /// 嵌套打开子ui /// - public UiBase OpenNestedUi(string uiName, UiBase prevUi = null); + UiBase OpenNestedUi(string uiName, UiBase prevUi = null); /// /// 嵌套打开子ui /// - public T OpenNestedUi(string uiName, UiBase prevUi = null) where T : UiBase; + T OpenNestedUi(string uiName, UiBase prevUi = null) where T : UiBase; /// /// 获取所属Ui面板 /// - public UiBase GetUiPanel(); + UiBase GetUiPanel(); /// /// 获取Ui实例 /// - public Node GetUiInstance(); + Node GetUiInstance(); /// /// 获取克隆的Ui实例 /// - public IUiCellNode CloneUiCell(); + IUiCellNode CloneUiCell(); } diff --git a/DungeonShooting_Godot/src/framework/ui/UiGridContainer.cs b/DungeonShooting_Godot/src/framework/ui/UiGridContainer.cs new file mode 100644 index 0000000..891fe33 --- /dev/null +++ b/DungeonShooting_Godot/src/framework/ui/UiGridContainer.cs @@ -0,0 +1,27 @@ +using System; +using Godot; + +/// +/// 用于 UiGrid 类 +/// +public partial class UiGridContainer : GridContainer +{ + private Action _onReady; + private Action _onProcess; + + public UiGridContainer(Action onReady, Action onProcess) + { + _onReady = onReady; + _onProcess = onProcess; + } + + public override void _Ready() + { + _onReady(); + } + + public override void _Process(double delta) + { + _onProcess((float)delta); + } +} \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/ui/grid/IUiCell.cs b/DungeonShooting_Godot/src/framework/ui/grid/IUiCell.cs index 4b4e239..379abd9 100644 --- a/DungeonShooting_Godot/src/framework/ui/grid/IUiCell.cs +++ b/DungeonShooting_Godot/src/framework/ui/grid/IUiCell.cs @@ -5,23 +5,71 @@ public interface IUiCell : IDestroy { /// + /// 是否启用了当前 Cell + /// + bool Enable { get; } + + /// /// 当前 Cell 在 UiGrid 组件中的索引位置 /// - public int Index { get; } + int Index { get; } /// + /// 当前 Cell 初始化时调用 + /// + void OnInit(); + + /// + /// 如果启用了当前 Cell, 则调用 + /// + void Process(float delta); + + /// + /// 当前Ui被点击时调用
+ /// 如果 Cell 的模板为 BaseButton 类型, 则 UiCell 会自动绑定点击事件
+ /// 如果需要自己绑定点击事件, 请绑定 UiCell.Click() 函数
+ /// 如果当前 Cell 未被选中, 则 OnSelect() 会比 OnClick() 先调用 + ///
+ void OnClick(); + + /// + /// 双击当前 Cell 调用 + /// + void OnDoubleClick(); + + /// + /// 当启用当前 Cell 时调用 + /// + void OnEnable(); + + /// + /// 当禁用当前 Cell 时调用, 也就是被回收时调用 + /// + void OnDisable(); + + /// /// 当检测当前 Cell 是否可以被选中时调用 /// - public bool CanSelect(); + bool CanSelect(); /// /// 当前 Cell 选中时调用, 设置 UiGrid.SelectIndex 时触发 /// - public void OnSelect(); + void OnSelect(); /// /// 当前 Cell 取消选中时调用, 设置 UiGrid.SelectIndex 时触发 /// - public void OnUnSelect(); + void OnUnSelect(); + /// + /// 当 Cell 索引发生改变时调用, 在 UiGrid 中调用 Insert(), Remove() 等函数时被动触发当前 Cell 索引值改变, Cell 业务逻辑需要用到索引值时, 那么就可以重写该函数
+ /// 注意: 该函数第一次调用会在 OnSetData() 之前调用 + ///
+ void OnRefreshIndex(); + + /// + /// 销毁当前cell时调用 + /// + void OnDestroy(); } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/ui/grid/IUiGrid.cs b/DungeonShooting_Godot/src/framework/ui/grid/IUiGrid.cs index 2965328..ddcfe39 100644 --- a/DungeonShooting_Godot/src/framework/ui/grid/IUiGrid.cs +++ b/DungeonShooting_Godot/src/framework/ui/grid/IUiGrid.cs @@ -8,10 +8,10 @@ /// /// 当前选中的 Cell 索引 /// - public int SelectIndex { get; set; } + int SelectIndex { get; set; } /// /// 设置网格组件是否可见 /// - public bool Visible { get; set; } + bool Visible { get; set; } } \ No newline at end of file diff --git a/DungeonShooting_Godot/src/framework/ui/grid/UiCell.cs b/DungeonShooting_Godot/src/framework/ui/grid/UiCell.cs index 01f61ac..9828ba5 100644 --- a/DungeonShooting_Godot/src/framework/ui/grid/UiCell.cs +++ b/DungeonShooting_Godot/src/framework/ui/grid/UiCell.cs @@ -1,4 +1,5 @@  +using System; using Godot; /// @@ -10,6 +11,8 @@ { public bool IsDestroyed { get; private set; } + public bool Enable { get; private set; } + public int Index { get; private set; } = -1; /// @@ -28,10 +31,9 @@ public T Data { get; private set; } private bool _init = false; - - /// - /// 当前cell初始化时调用 - /// + //上一次点击的时间 + private long _prevClickTime = -1; + public virtual void OnInit() { } @@ -43,23 +45,23 @@ { } - /// - /// 当当前Ui被点击时调用, 如果 Cell 的模板为 BaseButton 类型, 则 UiCell 会自动绑定点击事件 - /// + + public virtual void Process(float delta) + { + } + public virtual void OnClick() { } - /// - /// 当启用当前 Cell 时调用 - /// + public virtual void OnDoubleClick() + { + } + public virtual void OnEnable() { } - - /// - /// 当禁用当前 Cell 时调用, 也就是被回收时调用 - /// + public virtual void OnDisable() { } @@ -76,18 +78,11 @@ public virtual void OnUnSelect() { } - - /// - /// 当 Cell 索引发生改变时调用, 在 UiGrid 中调用 Insert(), Remove() 等函数时被动触发当前 Cell 索引值改变, Cell 业务逻辑需要用到索引值时, 那么就可以重写该函数
- /// 注意: 该函数第一次调用会在 OnSetData() 之前调用 - ///
+ public virtual void OnRefreshIndex() { } - - /// - /// 销毁当前cell时调用 - /// + public virtual void OnDestroy() { } @@ -113,9 +108,9 @@ OnInit(); SetIndex(index); } - + /// - /// 设置当前cell的值, 这个函数由 UiGrid 调用 + /// 设置当前 Cell 的值, 该函数由 UiGrid 调用 /// public void SetData(T data) { @@ -124,7 +119,7 @@ } /// - /// 设置当前 Cell 的索引 + /// 设置当前 Cell 的索引, 该函数由 UiGrid 对象调用 /// public void SetIndex(int index) { @@ -136,12 +131,44 @@ } /// + /// 设置是否启用该 Cell, 该函数由 UiGrid 对象调用 + /// + public void SetEnable(bool value) + { + Enable = value; + if (value) + { + OnEnable(); + } + else + { + OnDisable(); + } + } + + /// /// 触发点击当前Ui, 如果 Cell 的模板为 BaseButton 类型, 则 UiCell 会自动绑定点击事件 /// public void Click() { Grid.SelectIndex = Index; OnClick(); + + //双击判定 + if (_prevClickTime >= 0) + { + var now = DateTime.Now.Ticks / 10000; + if (now <= _prevClickTime + 500) + { + OnDoubleClick(); + } + + _prevClickTime = -1; + } + else + { + _prevClickTime = DateTime.Now.Ticks / 10000; + } } public void Destroy() diff --git a/DungeonShooting_Godot/src/framework/ui/grid/UiGrid.cs b/DungeonShooting_Godot/src/framework/ui/grid/UiGrid.cs index 29ab909..b65349c 100644 --- a/DungeonShooting_Godot/src/framework/ui/grid/UiGrid.cs +++ b/DungeonShooting_Godot/src/framework/ui/grid/UiGrid.cs @@ -68,7 +68,7 @@ //当前已被回收的cell池 private List> _cellList = new List>(); //godot原生网格组件 - private GridContainer _gridContainer; + private UiGridContainer _gridContainer; //单个cell偏移 private Vector2I _cellOffset; //列数 @@ -80,7 +80,7 @@ public UiGrid(TUiCellNode template, Type cellType) { - _gridContainer = new GridContainer(); + _gridContainer = new UiGridContainer(OnReady, OnProcess); _gridContainer.Ready += OnReady; _template = template; _cellType = cellType; @@ -344,15 +344,32 @@ _cellPool = null; _gridContainer.QueueFree(); } - + private void OnReady() { - _gridContainer.Ready -= OnReady; if (_template.GetUiInstance() is Control control) { _gridContainer.Position = control.Position; } } + + private void OnProcess(float delta) + { + if (IsDestroyed) + { + return; + } + //调用 cell 更新 + var uiCells = _cellPool.ToArray(); + for (var i = 0; i < uiCells.Length; i++) + { + var item = uiCells[i]; + if (item.Enable) + { + item.Process(delta); + } + } + } //获取 cell 实例 private UiCell GetCellInstance() @@ -361,7 +378,7 @@ { var cell = _cellPool.Pop(); cell.SetIndex(_cellList.Count); - cell.OnEnable(); + cell.SetEnable(true); _cellList.Add(cell); return cell; } @@ -374,14 +391,14 @@ _cellList.Add(uiCell); uiCell.Init(this, (TUiCellNode)_template.CloneUiCell(), _cellList.Count - 1); - uiCell.OnEnable(); + uiCell.SetEnable(true); return uiCell; } //回收 cell private void ReclaimCellInstance(UiCell cell) { - cell.OnDisable(); + cell.SetEnable(false); _gridContainer.RemoveChild(cell.CellNode.GetUiInstance()); _cellPool.Push(cell); } diff --git a/DungeonShooting_Godot/src/game/ui/mapEditorSelectObject/ObjectButtonCell.cs b/DungeonShooting_Godot/src/game/ui/mapEditorSelectObject/ObjectButtonCell.cs index 989d9a9..60c1fbe 100644 --- a/DungeonShooting_Godot/src/game/ui/mapEditorSelectObject/ObjectButtonCell.cs +++ b/DungeonShooting_Godot/src/game/ui/mapEditorSelectObject/ObjectButtonCell.cs @@ -1,4 +1,5 @@ using Config; +using Godot; namespace UI.MapEditorSelectObject;