mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-03-23 11:14:30 +08:00
feat(input): 移除旧版输入系统相关接口与实现
删除了游戏框架中原有的整套输入系统接口和实现类, 包括 IGameInputEvent、IInputContext、IInputTranslator、 InputContextStack、InputEvents、InputSystem 等定义。 同时移除了 Godot 模块中与之关联的输入桥接与翻译组件, 如 AbstractGodotInputModule、GodotInputBridge、 GodotInputTranslator 等,为重构或替换新的输入系统做准备。
This commit is contained in:
parent
cae1223fb5
commit
84ecd9fdc0
@ -9,6 +9,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="entities\" />
|
||||
<Folder Include="input\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GFramework.Core\GFramework.Core.csproj" />
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
namespace GFramework.Game.input;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏输入事件接口
|
||||
/// </summary>
|
||||
public interface IGameInputEvent;
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -21,4 +21,8 @@
|
||||
<Compile Remove="extensions\ControlExtensions.cs"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="input\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,19 +0,0 @@
|
||||
namespace GFramework.Godot.input;
|
||||
|
||||
/// <summary>
|
||||
/// 输入处理阶段枚举,用于区分Godot引擎中不同的输入处理阶段
|
||||
/// </summary>
|
||||
public enum GodotInputPhase
|
||||
{
|
||||
/// <summary>
|
||||
/// 捕获阶段,在_Input方法中处理输入事件
|
||||
/// 这是输入事件的第一个处理阶段,事件会沿着节点树向下传递
|
||||
/// </summary>
|
||||
Capture, // _Input
|
||||
|
||||
/// <summary>
|
||||
/// 冒泡阶段,在_UnhandledInput方法中处理输入事件
|
||||
/// 这是输入事件的第二个处理阶段,未被处理的事件会向上冒泡传递
|
||||
/// </summary>
|
||||
Bubble // _UnhandledInput
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user