diff --git a/GFramework.Core/constants/GFrameworkConstants.cs b/GFramework.Core/constants/GFrameworkConstants.cs new file mode 100644 index 0000000..ef0e309 --- /dev/null +++ b/GFramework.Core/constants/GFrameworkConstants.cs @@ -0,0 +1,12 @@ +namespace GFramework.Core.constants; + +/// +/// GFramework框架常量定义类 +/// +public static class GFrameworkConstants +{ + /// + /// 框架名称常量 + /// + public const string FrameworkName = "GFramework"; +} diff --git a/GFramework.Game/input/InputEvents.cs b/GFramework.Game/input/InputEvents.cs new file mode 100644 index 0000000..3e672e2 --- /dev/null +++ b/GFramework.Game/input/InputEvents.cs @@ -0,0 +1,33 @@ +using System.Numerics; + +namespace GFramework.Game.input; + +public static class InputEvents +{ + /// + /// 按键输入事件 + /// + /// 按键操作名称 + /// 按键是否被按下,true表示按下,false表示释放 + /// 是否为回显事件,用于处理按键重复触发 + public sealed record KeyInputEvent( + string Action, + bool Pressed, + bool Echo + ) : IGameInputEvent; + + /// + /// 指针/鼠标输入事件 + /// + /// 二维向量类型 + /// 指针当前位置坐标 + /// 指针位置变化量 + /// 鼠标按键编号,0表示左键,1表示右键,2表示中键 + /// 按键是否被按下,true表示按下,false表示释放 + public sealed record PointerInputEvent( + TVector2 Position, + TVector2 Delta, + int Button, + bool Pressed + ) : IGameInputEvent where TVector2 : struct; +} \ No newline at end of file diff --git a/GFramework.Godot/architecture/AbstractArchitecture.cs b/GFramework.Godot/architecture/AbstractArchitecture.cs index bd88d30..4d0476e 100644 --- a/GFramework.Godot/architecture/AbstractArchitecture.cs +++ b/GFramework.Godot/architecture/AbstractArchitecture.cs @@ -1,4 +1,5 @@ using GFramework.Core.architecture; +using GFramework.Core.constants; using GFramework.Godot.extensions; using Godot; @@ -16,7 +17,7 @@ public abstract class AbstractArchitecture : Architecture where T : Archit /// 架构锚点节点的唯一标识名称 /// 用于在Godot场景树中创建和查找架构锚点节点 /// - private const string ArchitectureName = "__GFramework__Architecture__Anchor"; + private const string ArchitectureAnchorName = $"__${GFrameworkConstants.FrameworkName}__ArchitectureAnchor__"; /// /// 存储所有已安装的Godot架构扩展组件列表 @@ -28,7 +29,7 @@ public abstract class AbstractArchitecture : Architecture where T : Archit /// 架构锚点节点引用 /// 用于将架构绑定到Godot生命周期并作为扩展节点的父节点 /// - private ArchitectureAnchorNode? _anchor; + private ArchitectureAnchor? _anchor; /// /// 获取架构根节点。如果尚未初始化或已被销毁,则抛出异常。 @@ -69,12 +70,12 @@ public abstract class AbstractArchitecture : Architecture where T : Archit return; // 防止重复挂载(热重载 / 多次 Init) - if (tree.Root.GetNodeOrNull(ArchitectureName) != null) + if (tree.Root.GetNodeOrNull(ArchitectureAnchorName) != null) return; - _anchor = new ArchitectureAnchorNode + _anchor = new ArchitectureAnchor { - Name = ArchitectureName + Name = ArchitectureAnchorName }; _anchor.Bind(Destroy); diff --git a/GFramework.Godot/architecture/AbstractGodotModule.cs b/GFramework.Godot/architecture/AbstractGodotModule.cs new file mode 100644 index 0000000..e89975b --- /dev/null +++ b/GFramework.Godot/architecture/AbstractGodotModule.cs @@ -0,0 +1,58 @@ +using GFramework.Core.architecture; +using Godot; + +namespace GFramework.Godot.architecture; + +/// +/// 抽象的Godot模块基类,用于定义Godot框架中的模块行为 +/// +/// 架构类型,必须继承自Architecture并且有无参构造函数 +public abstract class AbstractGodotModule: IGodotModule where T : Architecture, new() +{ + /// + /// 当架构阶段发生变化时调用此方法 + /// + /// 当前的架构阶段 + /// 架构实例 + public virtual void OnPhase(ArchitecturePhase phase, IArchitecture arch) + { + + } + + /// + /// 当架构阶段发生变化时调用此方法 + /// + /// 当前的架构阶段 + public virtual void OnArchitecturePhase(ArchitecturePhase phase) + { + + } + + /// + /// 安装模块到指定架构中 + /// + /// 要安装到的架构实例 + public abstract void Install(IArchitecture architecture); + + /// + /// 获取模块关联的Godot节点 + /// + public abstract Node Node { get; } + + /// + /// 当模块被附加到架构时调用此方法 + /// + /// 被附加到的架构实例 + public virtual void OnAttach(Architecture architecture) + { + + } + + /// + /// 当模块从架构中分离时调用此方法 + /// + public virtual void OnDetach() + { + + } +} diff --git a/GFramework.Godot/architecture/ArchitectureAnchorNode.cs b/GFramework.Godot/architecture/ArchitectureAnchor.cs similarity index 84% rename from GFramework.Godot/architecture/ArchitectureAnchorNode.cs rename to GFramework.Godot/architecture/ArchitectureAnchor.cs index ca1c0f4..4f41564 100644 --- a/GFramework.Godot/architecture/ArchitectureAnchorNode.cs +++ b/GFramework.Godot/architecture/ArchitectureAnchor.cs @@ -6,7 +6,7 @@ namespace GFramework.Godot.architecture; /// 架构锚点节点类,用于在Godot场景树中作为架构组件的根节点 /// 该类提供了退出时的回调绑定功能,可以在节点从场景树中移除时执行清理操作 /// -public partial class ArchitectureAnchorNode : Node +public partial class ArchitectureAnchor : Node { private Action? _onExit; /// @@ -18,7 +18,7 @@ public partial class ArchitectureAnchorNode : Node if (_onExit != null) { GD.PushWarning( - $"{nameof(ArchitectureAnchorNode)} already bound. Rebinding will override previous callback."); + $"{nameof(ArchitectureAnchor)} already bound. Rebinding will override previous callback."); } _onExit = onExit; } diff --git a/GFramework.Godot/system/AbstractResourceFactorySystem.cs b/GFramework.Godot/assets/AbstractResourceFactorySystem.cs similarity index 100% rename from GFramework.Godot/system/AbstractResourceFactorySystem.cs rename to GFramework.Godot/assets/AbstractResourceFactorySystem.cs diff --git a/GFramework.Godot/system/IResourceLoadSystem.cs b/GFramework.Godot/assets/IResourceLoadSystem.cs similarity index 100% rename from GFramework.Godot/system/IResourceLoadSystem.cs rename to GFramework.Godot/assets/IResourceLoadSystem.cs diff --git a/GFramework.Godot/system/ResourceLoadSystem.cs b/GFramework.Godot/assets/ResourceLoadSystem.cs similarity index 100% rename from GFramework.Godot/system/ResourceLoadSystem.cs rename to GFramework.Godot/assets/ResourceLoadSystem.cs diff --git a/GFramework.Godot/input/GodotInputBridge.cs b/GFramework.Godot/input/GodotInputBridge.cs new file mode 100644 index 0000000..7c89986 --- /dev/null +++ b/GFramework.Godot/input/GodotInputBridge.cs @@ -0,0 +1,79 @@ +using GFramework.Game.input; +using Godot; + +namespace GFramework.Godot.input; + +/// +/// Godot输入桥接类,用于将Godot的输入事件转换为游戏框架的输入事件 +/// +public partial class GodotInputBridge : Node +{ + private InputSystem _inputSystem = null!; + + /// + /// 绑定输入系统 + /// + /// 要绑定的输入系统实例 + public void Bind(InputSystem inputSystem) + { + _inputSystem = inputSystem; + } + + /// + /// 处理输入事件的回调方法 + /// + /// Godot输入事件 + public override void _Input(InputEvent @event) + { + var gameEvent = Translate(@event); + if (gameEvent == null) + { + return; + } + + _inputSystem.Handle(gameEvent); + GetViewport().SetInputAsHandled(); + } + + /// + /// 将Godot输入事件翻译为游戏框架输入事件 + /// + /// Godot输入事件 + /// 翻译后的游戏输入事件,如果无法翻译则返回null + private static IGameInputEvent? Translate(InputEvent evt) + { + // 处理动作输入事件 + if (evt is InputEventAction action) + { + return new InputEvents.KeyInputEvent( + action.Action, + action.Pressed, + false + ); + } + + // 鼠标按钮 + if (evt is InputEventMouseButton mb) + { + return new InputEvents.PointerInputEvent( + mb.Position, + Vector2.Zero, + (int)mb.ButtonIndex, + mb.Pressed + ); + } + + // 鼠标移动 + if (evt is InputEventMouseMotion mm) + { + return new InputEvents.PointerInputEvent( + mm.Position, + mm.Relative, + 0, + false + ); + } + + return null; + } +} diff --git a/GFramework.Godot/input/GodotInputModule.cs b/GFramework.Godot/input/GodotInputModule.cs new file mode 100644 index 0000000..9b020e3 --- /dev/null +++ b/GFramework.Godot/input/GodotInputModule.cs @@ -0,0 +1,61 @@ +using GFramework.Core.architecture; +using GFramework.Core.constants; +using GFramework.Game.input; +using GFramework.Godot.architecture; +using GFramework.Godot.extensions; +using Godot; + +namespace GFramework.Godot.input; + +/// +/// Godot输入模块类,用于管理Godot游戏引擎中的输入系统 +/// +/// 架构类型,必须继承自Architecture且具有无参构造函数 +public sealed class GodotInputModule : AbstractGodotModule + where T : Architecture, new() +{ + private GodotInputBridge? _node; + /// + /// 架构锚点节点的唯一标识名称 + /// 用于在Godot场景树中创建和查找架构锚点节点 + /// + private const string GodotInputBridgeName = $"__${GFrameworkConstants.FrameworkName}__GodotInputBridge__"; + /// + /// 获取模块对应的节点对象 + /// + /// 当节点尚未创建时抛出异常 + public override Node Node => _node + ?? throw new InvalidOperationException("Node not created yet"); + private InputSystem _inputSystem = null!; + + /// + /// 当模块被附加到架构时调用此方法 + /// + /// 要附加到的架构实例 + public override void OnAttach(Architecture architecture) + { + // 创建Godot输入桥接节点并绑定输入系统 + _node = new GodotInputBridge { Name = GodotInputBridgeName}; + _node.Bind(_inputSystem); + } + + /// + /// 当模块从架构中分离时调用此方法 + /// + public override void OnDetach() + { + // 释放节点资源并清理引用 + Node.QueueFreeX(); + _node = null; + } + + /// + /// 安装模块时调用此方法,用于获取所需的系统组件 + /// + /// 当前架构实例 + public override void Install(IArchitecture architecture) + { + // 从架构中获取输入系统实例 + _inputSystem = architecture.GetSystem()!; + } +} diff --git a/GFramework.sln.DotSettings.user b/GFramework.sln.DotSettings.user new file mode 100644 index 0000000..c18f938 --- /dev/null +++ b/GFramework.sln.DotSettings.user @@ -0,0 +1,2 @@ + + ForceIncluded \ No newline at end of file