diff --git a/GFramework.Core.Godot/GFramework.Core.Godot.csproj b/GFramework.Core.Godot/GFramework.Core.Godot.csproj index a9178c9..9526647 100644 --- a/GFramework.Core.Godot/GFramework.Core.Godot.csproj +++ b/GFramework.Core.Godot/GFramework.Core.Godot.csproj @@ -16,4 +16,8 @@ + + + + diff --git a/GFramework.Core.Godot/extensions/NodeExtensions.cs b/GFramework.Core.Godot/extensions/NodeExtensions.cs index 3317682..5b5522d 100644 --- a/GFramework.Core.Godot/extensions/NodeExtensions.cs +++ b/GFramework.Core.Godot/extensions/NodeExtensions.cs @@ -1,5 +1,8 @@ -using Godot; -namespace GFramework.Core.Godot.godot.extensions; +using System; +using System.Threading.Tasks; +using Godot; + +namespace GFramework.Core.Godot.extensions; /// /// 节点扩展方法类,提供对Godot节点的扩展功能 @@ -101,4 +104,165 @@ public static class NodeExtensions !GodotObject.IsInstanceValid(node) || !node.IsInsideTree(); } + + /// + /// 将当前节点的输入事件标记为已处理,防止事件继续向父节点传播。 + /// + /// 要处理输入事件的节点实例 + public static void SetInputAsHandled(this Node node) + { + // 获取节点的视口并标记输入事件为已处理 + node.GetViewport().SetInputAsHandled(); + } + + /// + /// 设置节点所在场景树的暂停状态 + /// + /// 要操作的节点对象 + /// 暂停状态标识,默认为true表示暂停,false表示恢复运行 + public static void Paused(this Node node, bool paused = true) + { + var tree = node.GetTree(); + tree.Paused = paused; + } + + /// + /// 查找指定名称的子节点并将其转换为指定类型 + /// + /// 要转换到的目标节点类型 + /// 要在其子节点中进行查找的父节点 + /// 要查找的子节点名称 + /// 是否递归查找所有层级的子节点,默认为true + /// 找到的子节点转换为指定类型后的结果,如果未找到或转换失败则返回null + public static T? FindChildX(this Node node, string name, bool recursive = true) + where T : Node + { + var child = node.FindChild(name, recursive, owned: false); + return child as T; + } + + /// + /// 获取指定路径的节点,如果不存在则创建一个新的节点 + /// + /// 节点类型,必须继承自Node且具有无参构造函数 + /// 父节点 + /// 节点路径 + /// 找到的现有节点或新创建的节点 + public static T GetOrCreateNode(this Node node, string path) + where T : Node, new() + { + // 尝试获取现有节点 + if (node.GetNodeOrNull(path) is { } found) + return found; + + // 创建新节点并添加到父节点 + var created = new T(); + node.AddChild(created); + created.Name = path; + return created; + } + + /// + /// 异步添加子节点并等待其准备就绪 + /// + /// 父节点 + /// 要添加的子节点 + /// 异步任务 + public static async Task AddChildX(this Node parent, Node child) + { + parent.AddChild(child); + await child.WaitUntilReady(); + } + + /// + /// 获取父节点并将其转换为指定类型 + /// + /// 要转换到的目标节点类型 + /// 当前节点 + /// 父节点转换为指定类型后的结果,如果转换失败则返回null + public static T? GetParentX(this Node node) where T : Node + { + return node.GetParent() as T; + } + /// + /// 获取场景树的根节点的第一个子节点 + /// + /// 扩展方法的目标节点 + /// 根节点的第一个子节点 + public static Node GetRootNodeX(this Node node) + { + return node.GetTree().Root.GetChild(0); + } + + /// + /// 遍历节点的所有子节点,并对指定类型的子节点执行特定操作 + /// + /// 要筛选的节点类型 + /// 扩展方法的目标节点 + /// 对符合条件的子节点执行的操作 + public static void ForEachChild(this Node node, Action action) where T : Node + { + foreach (var child in node.GetChildren()) + if (child is T t) + action(t); + } + + /// + /// 禁用节点所在场景树的输入处理功能 + /// + /// 扩展方法的目标节点 + public static void DisableInput(this Node node) + { + // 检查根节点是否为Viewport类型,如果是则禁用GUI输入 + if (node.GetTree().Root is Viewport vp) + vp.GuiDisableInput = true; + } + + /// + /// 启用节点所在场景树的输入处理功能 + /// + /// 扩展方法的目标节点 + public static void EnableInput(this Node node) + { + // 检查根节点是否为Viewport类型,如果是则启用GUI输入 + if (node.GetTree().Root is Viewport vp) + vp.GuiDisableInput = false; + } + + /// + /// 打印节点的路径信息到控制台 + /// + /// 扩展方法的目标节点 + public static void LogNodePath(this Node node) + { + GD.Print($"[NodePath] {node.GetPath()}"); + } + + /// + /// 以树形结构递归打印节点及其所有子节点的名称 + /// + /// 扩展方法的目标节点 + /// 缩进字符串,用于显示层级关系 + public static void PrintTreeX(this Node node, string indent = "") + { + GD.Print($"{indent}- {node.Name}"); + + // 递归打印所有子节点 + foreach (var child in node.GetChildren()) + child.PrintTreeX(indent + " "); + } + + /// + /// 安全地延迟调用指定方法,确保节点有效后再执行 + /// + /// 扩展方法的目标节点 + /// 要延迟调用的方法名 + public static void SafeCallDeferred(this Node? node, string method) + { + // 检查节点是否为空且实例是否有效,有效时才执行延迟调用 + if (node != null && GodotObject.IsInstanceValid(node)) + node.CallDeferred(method); + } + + } \ No newline at end of file