mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-22 19:03:29 +08:00
feat(GFramework.Godot): 引入 Godot 输入模块与架构锚点重构
新增 GodotInputModule 和相关输入事件类型,实现 Godot 输入系统与游戏框架的桥接。 重构架构锚点类名及其引用,统一使用 GFrameworkConstants 中定义的框架名称常量。 添加 AbstractGodotModule 基类以规范模块行为,并完善输入事件记录类定义。
This commit is contained in:
parent
bb403bd454
commit
12e257d16f
12
GFramework.Core/constants/GFrameworkConstants.cs
Normal file
12
GFramework.Core/constants/GFrameworkConstants.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace GFramework.Core.constants;
|
||||
|
||||
/// <summary>
|
||||
/// GFramework框架常量定义类
|
||||
/// </summary>
|
||||
public static class GFrameworkConstants
|
||||
{
|
||||
/// <summary>
|
||||
/// 框架名称常量
|
||||
/// </summary>
|
||||
public const string FrameworkName = "GFramework";
|
||||
}
|
||||
33
GFramework.Game/input/InputEvents.cs
Normal file
33
GFramework.Game/input/InputEvents.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace GFramework.Game.input;
|
||||
|
||||
public static class InputEvents
|
||||
{
|
||||
/// <summary>
|
||||
/// 按键输入事件
|
||||
/// </summary>
|
||||
/// <param name="Action">按键操作名称</param>
|
||||
/// <param name="Pressed">按键是否被按下,true表示按下,false表示释放</param>
|
||||
/// <param name="Echo">是否为回显事件,用于处理按键重复触发</param>
|
||||
public sealed record KeyInputEvent(
|
||||
string Action,
|
||||
bool Pressed,
|
||||
bool Echo
|
||||
) : IGameInputEvent;
|
||||
|
||||
/// <summary>
|
||||
/// 指针/鼠标输入事件
|
||||
/// </summary>
|
||||
/// <typeparam name="TVector2">二维向量类型</typeparam>
|
||||
/// <param name="Position">指针当前位置坐标</param>
|
||||
/// <param name="Delta">指针位置变化量</param>
|
||||
/// <param name="Button">鼠标按键编号,0表示左键,1表示右键,2表示中键</param>
|
||||
/// <param name="Pressed">按键是否被按下,true表示按下,false表示释放</param>
|
||||
public sealed record PointerInputEvent<TVector2>(
|
||||
TVector2 Position,
|
||||
TVector2 Delta,
|
||||
int Button,
|
||||
bool Pressed
|
||||
) : IGameInputEvent where TVector2 : struct;
|
||||
}
|
||||
@ -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<T> : Architecture<T> where T : Archit
|
||||
/// 架构锚点节点的唯一标识名称
|
||||
/// 用于在Godot场景树中创建和查找架构锚点节点
|
||||
/// </summary>
|
||||
private const string ArchitectureName = "__GFramework__Architecture__Anchor";
|
||||
private const string ArchitectureAnchorName = $"__${GFrameworkConstants.FrameworkName}__ArchitectureAnchor__";
|
||||
|
||||
/// <summary>
|
||||
/// 存储所有已安装的Godot架构扩展组件列表
|
||||
@ -28,7 +29,7 @@ public abstract class AbstractArchitecture<T> : Architecture<T> where T : Archit
|
||||
/// 架构锚点节点引用
|
||||
/// 用于将架构绑定到Godot生命周期并作为扩展节点的父节点
|
||||
/// </summary>
|
||||
private ArchitectureAnchorNode? _anchor;
|
||||
private ArchitectureAnchor? _anchor;
|
||||
|
||||
/// <summary>
|
||||
/// 获取架构根节点。如果尚未初始化或已被销毁,则抛出异常。
|
||||
@ -69,12 +70,12 @@ public abstract class AbstractArchitecture<T> : Architecture<T> 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);
|
||||
|
||||
58
GFramework.Godot/architecture/AbstractGodotModule.cs
Normal file
58
GFramework.Godot/architecture/AbstractGodotModule.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using GFramework.Core.architecture;
|
||||
using Godot;
|
||||
|
||||
namespace GFramework.Godot.architecture;
|
||||
|
||||
/// <summary>
|
||||
/// 抽象的Godot模块基类,用于定义Godot框架中的模块行为
|
||||
/// </summary>
|
||||
/// <typeparam name="T">架构类型,必须继承自Architecture并且有无参构造函数</typeparam>
|
||||
public abstract class AbstractGodotModule<T>: IGodotModule<T> where T : Architecture<T>, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// 当架构阶段发生变化时调用此方法
|
||||
/// </summary>
|
||||
/// <param name="phase">当前的架构阶段</param>
|
||||
/// <param name="arch">架构实例</param>
|
||||
public virtual void OnPhase(ArchitecturePhase phase, IArchitecture arch)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当架构阶段发生变化时调用此方法
|
||||
/// </summary>
|
||||
/// <param name="phase">当前的架构阶段</param>
|
||||
public virtual void OnArchitecturePhase(ArchitecturePhase phase)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装模块到指定架构中
|
||||
/// </summary>
|
||||
/// <param name="architecture">要安装到的架构实例</param>
|
||||
public abstract void Install(IArchitecture architecture);
|
||||
|
||||
/// <summary>
|
||||
/// 获取模块关联的Godot节点
|
||||
/// </summary>
|
||||
public abstract Node Node { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当模块被附加到架构时调用此方法
|
||||
/// </summary>
|
||||
/// <param name="architecture">被附加到的架构实例</param>
|
||||
public virtual void OnAttach(Architecture<T> architecture)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当模块从架构中分离时调用此方法
|
||||
/// </summary>
|
||||
public virtual void OnDetach()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@ namespace GFramework.Godot.architecture;
|
||||
/// 架构锚点节点类,用于在Godot场景树中作为架构组件的根节点
|
||||
/// 该类提供了退出时的回调绑定功能,可以在节点从场景树中移除时执行清理操作
|
||||
/// </summary>
|
||||
public partial class ArchitectureAnchorNode : Node
|
||||
public partial class ArchitectureAnchor : Node
|
||||
{
|
||||
private Action? _onExit;
|
||||
/// <summary>
|
||||
@ -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;
|
||||
}
|
||||
79
GFramework.Godot/input/GodotInputBridge.cs
Normal file
79
GFramework.Godot/input/GodotInputBridge.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using GFramework.Game.input;
|
||||
using Godot;
|
||||
|
||||
namespace GFramework.Godot.input;
|
||||
|
||||
/// <summary>
|
||||
/// Godot输入桥接类,用于将Godot的输入事件转换为游戏框架的输入事件
|
||||
/// </summary>
|
||||
public partial class GodotInputBridge : Node
|
||||
{
|
||||
private InputSystem _inputSystem = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 绑定输入系统
|
||||
/// </summary>
|
||||
/// <param name="inputSystem">要绑定的输入系统实例</param>
|
||||
public void Bind(InputSystem inputSystem)
|
||||
{
|
||||
_inputSystem = inputSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理输入事件的回调方法
|
||||
/// </summary>
|
||||
/// <param name="event">Godot输入事件</param>
|
||||
public override void _Input(InputEvent @event)
|
||||
{
|
||||
var gameEvent = Translate(@event);
|
||||
if (gameEvent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_inputSystem.Handle(gameEvent);
|
||||
GetViewport().SetInputAsHandled();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将Godot输入事件翻译为游戏框架输入事件
|
||||
/// </summary>
|
||||
/// <param name="evt">Godot输入事件</param>
|
||||
/// <returns>翻译后的游戏输入事件,如果无法翻译则返回null</returns>
|
||||
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<Vector2>(
|
||||
mb.Position,
|
||||
Vector2.Zero,
|
||||
(int)mb.ButtonIndex,
|
||||
mb.Pressed
|
||||
);
|
||||
}
|
||||
|
||||
// 鼠标移动
|
||||
if (evt is InputEventMouseMotion mm)
|
||||
{
|
||||
return new InputEvents.PointerInputEvent<Vector2>(
|
||||
mm.Position,
|
||||
mm.Relative,
|
||||
0,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
61
GFramework.Godot/input/GodotInputModule.cs
Normal file
61
GFramework.Godot/input/GodotInputModule.cs
Normal file
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Godot输入模块类,用于管理Godot游戏引擎中的输入系统
|
||||
/// </summary>
|
||||
/// <typeparam name="T">架构类型,必须继承自Architecture且具有无参构造函数</typeparam>
|
||||
public sealed class GodotInputModule<T> : AbstractGodotModule<T>
|
||||
where T : Architecture<T>, new()
|
||||
{
|
||||
private GodotInputBridge? _node;
|
||||
/// <summary>
|
||||
/// 架构锚点节点的唯一标识名称
|
||||
/// 用于在Godot场景树中创建和查找架构锚点节点
|
||||
/// </summary>
|
||||
private const string GodotInputBridgeName = $"__${GFrameworkConstants.FrameworkName}__GodotInputBridge__";
|
||||
/// <summary>
|
||||
/// 获取模块对应的节点对象
|
||||
/// </summary>
|
||||
/// <exception cref="InvalidOperationException">当节点尚未创建时抛出异常</exception>
|
||||
public override Node Node => _node
|
||||
?? throw new InvalidOperationException("Node not created yet");
|
||||
private InputSystem _inputSystem = null!;
|
||||
|
||||
/// <summary>
|
||||
/// 当模块被附加到架构时调用此方法
|
||||
/// </summary>
|
||||
/// <param name="architecture">要附加到的架构实例</param>
|
||||
public override void OnAttach(Architecture<T> architecture)
|
||||
{
|
||||
// 创建Godot输入桥接节点并绑定输入系统
|
||||
_node = new GodotInputBridge { Name = GodotInputBridgeName};
|
||||
_node.Bind(_inputSystem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当模块从架构中分离时调用此方法
|
||||
/// </summary>
|
||||
public override void OnDetach()
|
||||
{
|
||||
// 释放节点资源并清理引用
|
||||
Node.QueueFreeX();
|
||||
_node = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安装模块时调用此方法,用于获取所需的系统组件
|
||||
/// </summary>
|
||||
/// <param name="architecture">当前架构实例</param>
|
||||
public override void Install(IArchitecture architecture)
|
||||
{
|
||||
// 从架构中获取输入系统实例
|
||||
_inputSystem = architecture.GetSystem<InputSystem>()!;
|
||||
}
|
||||
}
|
||||
2
GFramework.sln.DotSettings.user
Normal file
2
GFramework.sln.DotSettings.user
Normal file
@ -0,0 +1,2 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AInputEventAction_002Ecs_002Fl_003AD_0021_003FTool_003FDevelopment_0020Tools_003FJetBrains_003F_002EJetBrains_003F_002ERider_003Fconfig_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F1c378f459c054fecaf4484a0fa6d44c055a800_003F18_003F33b52a1c_003FInputEventAction_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
Loading…
x
Reference in New Issue
Block a user