feat(input): 移除旧版输入系统相关接口与实现

删除了游戏框架中原有的整套输入系统接口和实现类,
包括 IGameInputEvent、IInputContext、IInputTranslator、
InputContextStack、InputEvents、InputSystem 等定义。

同时移除了 Godot 模块中与之关联的输入桥接与翻译组件,
如 AbstractGodotInputModule、GodotInputBridge、
GodotInputTranslator 等,为重构或替换新的输入系统做准备。
This commit is contained in:
GwWuYou 2025-12-22 20:23:06 +08:00
parent cae1223fb5
commit 84ecd9fdc0
13 changed files with 5 additions and 424 deletions

View File

@ -9,6 +9,7 @@
<ItemGroup>
<Folder Include="entities\" />
<Folder Include="input\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj" />

View File

@ -1,6 +0,0 @@
namespace GFramework.Game.input;
/// <summary>
/// 游戏输入事件接口
/// </summary>
public interface IGameInputEvent;

View File

@ -1,14 +0,0 @@
namespace GFramework.Game.input;
/// <summary>
/// 输入上下文接口,用于处理游戏中的输入事件
/// </summary>
public interface IInputContext
{
/// <summary>
/// 处理游戏输入事件
/// </summary>
/// <param name="input">要处理的游戏输入事件</param>
/// <returns>返回 true 表示输入被吃掉,不再向下传播;返回 false 表示输入未被处理,可以继续传播给其他处理器</returns>
bool Handle(IGameInputEvent input);
}

View File

@ -1,15 +0,0 @@
namespace GFramework.Game.input;
/// <summary>
/// 输入转换器接口
/// </summary>
public interface IInputTranslator
{
/// <summary>
/// 尝试将引擎输入翻译为游戏输入
/// </summary>
/// <param name="rawInput">原始的引擎输入对象</param>
/// <param name="gameEvent">输出参数,如果翻译成功则包含对应的游戏输入事件</param>
/// <returns>如果翻译成功返回true否则返回false</returns>
bool TryTranslate(object rawInput, out IGameInputEvent gameEvent);
}

View File

@ -1,54 +0,0 @@
namespace GFramework.Game.input;
/// <summary>
/// 输入上下文堆栈管理器,用于管理多个输入上下文的堆栈结构
/// </summary>
public class InputContextStack
{
private readonly Stack<IInputContext> _stack = new();
/// <summary>
/// 将指定的输入上下文压入堆栈顶部
/// </summary>
/// <param name="context">要压入堆栈的输入上下文对象</param>
public void Push(IInputContext context) => _stack.Push(context);
/// <summary>
/// 弹出堆栈顶部的元素
/// </summary>
public void Pop() => _stack.Pop();
/// <summary>
/// 弹出堆栈顶部的输入上下文
/// </summary>
/// <param name="ctx">要弹出的输入上下文对象</param>
/// <returns>如果成功弹出返回true否则返回false</returns>
public bool Pop(IInputContext ctx)
{
// 检查堆栈顶部元素是否与指定上下文匹配如果不匹配则返回false
if (!_stack.TryPeek(out var top) || top != ctx) return false;
_stack.Pop();
return true;
}
/// <summary>
/// 获取堆栈顶部的输入上下文但不移除它
/// </summary>
/// <returns>堆栈顶部的输入上下文</returns>
public IInputContext Peek() => _stack.Peek();
/// <summary>
/// 处理游戏输入事件
/// </summary>
/// <param name="input">要处理的游戏输入事件</param>
/// <returns>如果任何一个输入上下文成功处理了输入事件则返回true否则返回false</returns>
public bool Handle(IGameInputEvent input)
{
// 从堆栈顶部开始遍历输入上下文,尝试处理输入事件
return _stack.Any(ctx => ctx.Handle(input));
}
}

View File

@ -1,31 +0,0 @@
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;
}

View File

@ -1,86 +0,0 @@
using GFramework.Core.extensions;
using GFramework.Core.system;
namespace GFramework.Game.input;
/// <summary>
/// 输入系统类,负责管理输入上下文堆栈并处理游戏输入事件
/// </summary>
public class InputSystem : AbstractSystem
{
private readonly List<IInputTranslator> _translators = [];
private readonly InputContextStack _contextStack = new();
/// <summary>
/// 将输入上下文推入上下文堆栈
/// </summary>
/// <param name="ctx">要推入的输入上下文对象</param>
public void PushContext(IInputContext ctx)
=> _contextStack.Push(ctx);
/// <summary>
/// 从上下文堆栈中弹出顶层输入上下文
/// </summary>
public void PopContext()
=> _contextStack.Pop();
/// <summary>
/// 处理游戏输入事件,首先尝试通过上下文堆栈处理,如果未被处理则发送事件
/// </summary>
/// <param name="input">要处理的游戏输入事件</param>
public void Handle(IGameInputEvent input)
{
// 尝试通过上下文堆栈处理输入事件
if (_contextStack.Handle(input))
return;
// 如果上下文堆栈未能处理,则发送该事件
this.SendEvent(input);
}
/// <summary>
/// 系统初始化方法,在系统启动时调用
/// </summary>
protected override void OnInit()
{
}
/// <summary>
/// 注销输入转换器
/// </summary>
/// <param name="translator">要注销的输入转换器接口实例</param>
public void UnregisterTranslator(IInputTranslator translator)
=> _translators.Remove(translator);
/// <summary>
/// 注册输入转换器
/// </summary>
/// <param name="translator">输入转换器接口实例</param>
/// <param name="highPriority">是否为高优先级true时插入到转换器列表开头false时添加到列表末尾</param>
public void RegisterTranslator(IInputTranslator translator, bool highPriority = false)
{
if (_translators.Contains(translator))
return;
// 根据优先级设置决定插入位置
if (highPriority)
_translators.Insert(0, translator);
else
_translators.Add(translator);
}
/// <summary>
/// 处理原始输入数据
/// </summary>
/// <param name="rawInput">原始输入对象</param>
public void HandleRaw(object rawInput)
{
// 遍历所有注册的转换器,尝试将原始输入转换为游戏事件
foreach (var t in _translators)
{
if (!t.TryTranslate(rawInput, out var gameEvent)) continue;
Handle(gameEvent);
}
}
}

View File

@ -21,4 +21,8 @@
<Compile Remove="extensions\ControlExtensions.cs"/>
</ItemGroup>
<ItemGroup>
<Folder Include="input\" />
</ItemGroup>
</Project>

View File

@ -1,69 +0,0 @@
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 abstract class AbstractGodotInputModule<T> : AbstractGodotModule<T>
where T : Architecture<T>, new()
{
private GodotInputBridge? _node;
/// <summary>
/// 启用默认的输入转换器
/// </summary>
protected virtual bool EnableDefaultTranslator => false;
/// <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");
public override void OnDetach()
{
// 释放节点资源并清理引用
Node.QueueFreeX();
_node = null;
}
/// <summary>
/// 安装模块时调用此方法,用于获取所需的系统组件
/// </summary>
/// <param name="architecture">当前架构实例</param>
public override void Install(IArchitecture architecture)
{
// 从架构中获取输入系统实例
var inputSystem = architecture.GetSystem<InputSystem>()!;
if (EnableDefaultTranslator)
{
// 注册输入转换器
inputSystem.RegisterTranslator(new GodotInputTranslator(), true);
}
RegisterTranslator(inputSystem);
// 创建Godot输入桥接节点并绑定输入系统
_node = new GodotInputBridge { Name = GodotInputBridgeName };
_node.Bind(inputSystem);
}
/// <summary>
/// 注册翻译器的抽象方法,由子类实现具体的注册逻辑
/// </summary>
/// <param name="inputSystem">输入系统实例</param>
protected abstract void RegisterTranslator(InputSystem inputSystem);
}

View File

@ -1,41 +0,0 @@
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>
public override void _Input(InputEvent @event)
{
_inputSystem.HandleRaw(
new GodotRawInput(@event, GodotInputPhase.Capture)
);
}
/// <summary>
/// 冒泡阶段UI 未处理
/// </summary>
public override void _UnhandledInput(InputEvent @event)
{
_inputSystem.HandleRaw(
new GodotRawInput(@event, GodotInputPhase.Bubble)
);
}
}

View File

@ -1,19 +0,0 @@
namespace GFramework.Godot.input;
/// <summary>
/// 输入处理阶段枚举用于区分Godot引擎中不同的输入处理阶段
/// </summary>
public enum GodotInputPhase
{
/// <summary>
/// 捕获阶段在_Input方法中处理输入事件
/// 这是输入事件的第一个处理阶段,事件会沿着节点树向下传递
/// </summary>
Capture, // _Input
/// <summary>
/// 冒泡阶段在_UnhandledInput方法中处理输入事件
/// 这是输入事件的第二个处理阶段,未被处理的事件会向上冒泡传递
/// </summary>
Bubble // _UnhandledInput
}

View File

@ -1,68 +0,0 @@
using GFramework.Game.input;
using Godot;
namespace GFramework.Godot.input;
/// <summary>
/// 将Godot引擎的输入事件转换为游戏通用输入事件的翻译器
/// </summary>
public sealed class GodotInputTranslator : IInputTranslator
{
/// <summary>
/// 尝试将原始输入对象转换为游戏输入事件
/// </summary>
/// <param name="rawInput">原始输入对象应为Godot的InputEvent类型</param>
/// <param name="gameEvent">输出参数转换成功时返回对应的游戏输入事件失败时返回null</param>
/// <returns>转换成功返回true否则返回false</returns>
public bool TryTranslate(object rawInput, out IGameInputEvent gameEvent)
{
gameEvent = null!;
if (rawInput is not GodotRawInput raw)
return false;
var evt = raw.Event;
// 支持多个输入阶段Capture, Bubble, 和其他阶段
// 在拖拽过程中可能需要在Capture阶段也处理输入
if (raw.Phase != GodotInputPhase.Bubble && raw.Phase != GodotInputPhase.Capture)
return false;
// Action
if (evt is InputEventAction action)
{
gameEvent = new InputEvents.KeyInputEvent(
action.Action,
action.Pressed,
false
);
return true;
}
// Mouse button
if (evt is InputEventMouseButton mb)
{
gameEvent = new InputEvents.PointerInputEvent<Vector2>(
mb.Position,
Vector2.Zero,
(int)mb.ButtonIndex,
mb.Pressed
);
return true;
}
// Mouse motion
if (evt is InputEventMouseMotion mm)
{
gameEvent = new InputEvents.PointerInputEvent<Vector2>(
mm.Position,
mm.Relative,
0,
false
);
return true;
}
return false;
}
}

View File

@ -1,21 +0,0 @@
using Godot;
namespace GFramework.Godot.input;
/// <summary>
/// 表示Godot原始输入数据的只读结构体
/// </summary>
/// <param name="evt">输入事件对象</param>
/// <param name="phase">输入阶段</param>
public readonly struct GodotRawInput(InputEvent evt, GodotInputPhase phase)
{
/// <summary>
/// 获取输入事件对象
/// </summary>
public readonly InputEvent Event = evt;
/// <summary>
/// 获取输入阶段
/// </summary>
public readonly GodotInputPhase Phase = phase;
}