diff --git a/GFramework.Core/events/ArchitectureEvents.cs b/GFramework.Core/events/ArchitectureEvents.cs
index 53f0070..251e2a2 100644
--- a/GFramework.Core/events/ArchitectureEvents.cs
+++ b/GFramework.Core/events/ArchitectureEvents.cs
@@ -7,5 +7,5 @@ public static class ArchitectureEvents
/// 架构初始化完成事件
/// 在所有 Model / System Init 执行完毕后派发
///
- public readonly struct ArchitectureInitializedEvent { }
+ public readonly struct ArchitectureInitializedEvent;
}
\ No newline at end of file
diff --git a/GFramework.Game/input/IGameInputEvent.cs b/GFramework.Game/input/IGameInputEvent.cs
new file mode 100644
index 0000000..2a4d79e
--- /dev/null
+++ b/GFramework.Game/input/IGameInputEvent.cs
@@ -0,0 +1,6 @@
+namespace GFramework.Game.input;
+
+///
+/// 游戏输入事件接口
+///
+public interface IGameInputEvent;
diff --git a/GFramework.Game/input/IInputContext.cs b/GFramework.Game/input/IInputContext.cs
new file mode 100644
index 0000000..259a475
--- /dev/null
+++ b/GFramework.Game/input/IInputContext.cs
@@ -0,0 +1,14 @@
+namespace GFramework.Game.input;
+
+///
+/// 输入上下文接口,用于处理游戏中的输入事件
+///
+public interface IInputContext
+{
+ ///
+ /// 处理游戏输入事件
+ ///
+ /// 要处理的游戏输入事件
+ /// 返回 true 表示输入被吃掉,不再向下传播;返回 false 表示输入未被处理,可以继续传播给其他处理器
+ bool Handle(IGameInputEvent input);
+}
diff --git a/GFramework.Game/input/InputContextStack.cs b/GFramework.Game/input/InputContextStack.cs
new file mode 100644
index 0000000..358dde4
--- /dev/null
+++ b/GFramework.Game/input/InputContextStack.cs
@@ -0,0 +1,33 @@
+namespace GFramework.Game.input;
+
+///
+/// 输入上下文堆栈管理器,用于管理多个输入上下文的堆栈结构
+///
+public class InputContextStack
+{
+ private readonly Stack _stack = new();
+
+ ///
+ /// 将指定的输入上下文压入堆栈顶部
+ ///
+ /// 要压入堆栈的输入上下文对象
+ public void Push(IInputContext context) => _stack.Push(context);
+
+ ///
+ /// 弹出堆栈顶部的输入上下文
+ ///
+ public void Pop() => _stack.Pop();
+
+ ///
+ /// 处理游戏输入事件,遍历堆栈中的所有上下文直到找到能够处理该事件的上下文
+ ///
+ /// 要处理的游戏输入事件
+ /// 如果堆栈中任意一个上下文成功处理了输入事件则返回true,否则返回false
+ public bool Handle(IGameInputEvent input)
+ {
+ // 遍历堆栈中的所有上下文,调用其Handle方法处理输入事件
+ // Any方法会在第一个返回true的上下文处停止遍历
+ return _stack.Any(ctx => ctx.Handle(input));
+ }
+}
+
diff --git a/GFramework.Game/input/InputSystem.cs b/GFramework.Game/input/InputSystem.cs
new file mode 100644
index 0000000..796dfc6
--- /dev/null
+++ b/GFramework.Game/input/InputSystem.cs
@@ -0,0 +1,46 @@
+using GFramework.Core.extensions;
+using GFramework.Core.system;
+
+namespace GFramework.Game.input;
+
+///
+/// 输入系统类,负责管理输入上下文堆栈并处理游戏输入事件
+///
+public class InputSystem : AbstractSystem
+{
+ private readonly InputContextStack _contextStack = new();
+
+ ///
+ /// 将输入上下文推入上下文堆栈
+ ///
+ /// 要推入的输入上下文对象
+ public void PushContext(IInputContext ctx)
+ => _contextStack.Push(ctx);
+
+ ///
+ /// 从上下文堆栈中弹出顶层输入上下文
+ ///
+ public void PopContext()
+ => _contextStack.Pop();
+
+ ///
+ /// 处理游戏输入事件,首先尝试通过上下文堆栈处理,如果未被处理则发送事件
+ ///
+ /// 要处理的游戏输入事件
+ public void Handle(IGameInputEvent input)
+ {
+ // 尝试通过上下文堆栈处理输入事件
+ if (_contextStack.Handle(input))
+ return;
+ // 如果上下文堆栈未能处理,则发送该事件
+ this.SendEvent(input);
+ }
+
+ ///
+ /// 系统初始化方法,在系统启动时调用
+ ///
+ protected override void OnInit()
+ {
+
+ }
+}
diff --git a/GFramework.Godot/system/AbstractInputSystem.cs b/GFramework.Godot/system/AbstractInputSystem.cs
deleted file mode 100644
index cd70213..0000000
--- a/GFramework.Godot/system/AbstractInputSystem.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-using GFramework.Game.assets;
-
-namespace GFramework.Godot.system;
-
-///
-/// 抽象输入系统基类,实现了IInputSystem接口的基本功能
-///
-public abstract class AbstractInputSystem : AbstractAssetCatalogSystem, IInputSystem
-{
- // 存储动作名称与按键绑定的映射关系
- private readonly Dictionary _actionBindings = new();
-
- // 存储动作名称与当前状态的映射关系
- private readonly Dictionary _actionStates = new();
-
- // 存储动作名称与上一帧状态的映射关系
- private readonly Dictionary _previousActionStates = new();
-
- ///
- public virtual void SetBinding(string actionName, string keyCode)
- {
- _actionBindings[actionName] = keyCode;
- }
-
- ///
- public virtual string GetBinding(string actionName)
- {
- return _actionBindings.TryGetValue(actionName, out var binding) ? binding : string.Empty;
- }
-
- ///
- public virtual bool IsActionPressed(string actionName)
- {
- return _actionStates.TryGetValue(actionName, out var state) && state;
- }
-
- ///
- public virtual bool IsActionJustPressed(string actionName)
- {
- var current = _actionStates.TryGetValue(actionName, out var currentState) && currentState;
- var previous = _previousActionStates.TryGetValue(actionName, out var previousState) && previousState;
- return current && !previous;
- }
-
- ///
- public virtual bool IsActionJustReleased(string actionName)
- {
- var current = _actionStates.TryGetValue(actionName, out var currentState) && currentState;
- var previous = _previousActionStates.TryGetValue(actionName, out var previousState) && previousState;
- return !current && previous;
- }
-
- ///
- public virtual void AddAction(string actionName, string defaultKeyCode)
- {
- if (!_actionBindings.ContainsKey(actionName))
- {
- _actionBindings[actionName] = defaultKeyCode;
- _actionStates[actionName] = false;
- _previousActionStates[actionName] = false;
- }
- }
-
- ///
- public virtual void RemoveAction(string actionName)
- {
- _actionBindings.Remove(actionName);
- _actionStates.Remove(actionName);
- _previousActionStates.Remove(actionName);
- }
-
- ///
- public abstract void SaveConfiguration();
-
- ///
- public abstract void LoadConfiguration();
-
- ///
- public abstract void Update(double delta);
-
- ///
- /// 更新输入状态,在每一帧调用
- ///
- protected virtual void UpdateInputStates()
- {
- // 保存当前状态作为下一帧的前一状态
- foreach (var kvp in _actionStates)
- {
- _previousActionStates[kvp.Key] = kvp.Value;
- }
-
- // 更新当前状态
- foreach (var kvp in _actionBindings)
- {
- var actionName = kvp.Key;
- var keyCode = kvp.Value;
-
- // 这里需要根据具体平台和引擎实现具体的按键检测逻辑
- // 当前只是一个占位实现
- _actionStates[actionName] = CheckKeyPressed(keyCode);
- }
- }
-
- ///
- /// 检查特定按键是否被按下
- ///
- /// 按键码
- /// 按键是否被按下
- protected virtual bool CheckKeyPressed(string keyCode)
- {
- // 这里需要根据Godot引擎的具体实现来检查按键状态
- // 目前只是示例实现
- return false;
- }
-}
\ No newline at end of file
diff --git a/GFramework.Godot/system/GodotInputSystem.cs b/GFramework.Godot/system/GodotInputSystem.cs
deleted file mode 100644
index 4e2cfb6..0000000
--- a/GFramework.Godot/system/GodotInputSystem.cs
+++ /dev/null
@@ -1,195 +0,0 @@
-// using Godot;
-//
-// namespace GFramework.Godot.system;
-//
-// ///
-// /// Godot引擎专用的输入系统实现
-// ///
-// public class GodotInputSystem : AbstractInputSystem
-// {
-// private InputMap _inputMap;
-// private string _configPath;
-//
-// public override void Init()
-// {
-// base.Init();
-//
-// _inputMap = new InputMap();
-// _configPath = "user://input_config.json";
-//
-// // 添加一些默认的输入动作
-// AddDefaultActions();
-//
-// // 尝试加载用户配置
-// LoadConfiguration();
-// }
-//
-// public override void Destroy()
-// {
-// // 保存配置
-// SaveConfiguration();
-// base.Destroy();
-// }
-//
-// ///
-// /// 添加默认输入动作
-// ///
-// private void AddDefaultActions()
-// {
-// _inputMap.AddAction(new InputAction("move_left", InputActionType.Axis, "Left"));
-// _inputMap.AddAction(new InputAction("move_right", InputActionType.Axis, "Right"));
-// _inputMap.AddAction(new InputAction("move_up", InputActionType.Axis, "Up"));
-// _inputMap.AddAction(new InputAction("move_down", InputActionType.Axis, "Down"));
-// _inputMap.AddAction(new InputAction("jump", InputActionType.Button, "Space"));
-// _inputMap.AddAction(new InputAction("attack", InputActionType.Button, "LeftMouse"));
-// _inputMap.AddAction(new InputAction("interact", InputActionType.Button, "E"));
-// }
-//
-// ///
-// public override void SaveConfiguration()
-// {
-// try
-// {
-// var configData = new Dictionary();
-// foreach (var action in _inputMap.GetAllActions())
-// {
-// configData[action.Name] = action.CurrentBindings;
-// }
-//
-// var json = Json.Stringify(configData);
-// File.WriteAllText(ProjectSettings.GlobalizePath(_configPath), json);
-// }
-// catch (Exception ex)
-// {
-// GD.PrintErr($"Failed to save input configuration: {ex.Message}");
-// }
-// }
-//
-// ///
-// public override void LoadConfiguration()
-// {
-// try
-// {
-// if (!File.Exists(ProjectSettings.GlobalizePath(_configPath)))
-// {
-// // 配置文件不存在,使用默认配置
-// return;
-// }
-//
-// var json = File.ReadAllText(ProjectSettings.GlobalizePath(_configPath));
-// var parsed = Json.ParseString(json);
-// if (parsed is not Core.Godot.Collections.Dictionary dict)
-// {
-// GD.PrintErr("Invalid input configuration file");
-// return;
-// }
-//
-// foreach (var key in dict.Keys)
-// {
-// var action = _inputMap.GetAction(key.AsString());
-// if (action != null && dict[key] is Core.Godot.Collections.Array array)
-// {
-// var bindings = new string[array.Count];
-// for (int i = 0; i < array.Count; i++)
-// {
-// bindings[i] = array[i].AsString();
-// }
-// action.SetBindings(bindings);
-// }
-// }
-// }
-// catch (Exception ex)
-// {
-// GD.PrintErr($"Failed to load input configuration: {ex.Message}");
-// }
-// }
-//
-// ///
-// protected override bool CheckKeyPressed(string keyCode)
-// {
-// // 根据Godot的输入系统检查按键状态
-// return Input.IsPhysicalKeyPressed(GodotKeyMapper.GetKeyFromString(keyCode)) ||
-// Input.IsMouseButtonPressed(GodotKeyMapper.GetMouseButtonFromString(keyCode));
-// }
-//
-// ///
-// public override void Update(double delta)
-// {
-// UpdateInputStates();
-// }
-//
-// protected override void RegisterAssets()
-// {
-// throw new NotImplementedException();
-// }
-// }
-//
-// ///
-// /// Godot按键映射辅助类
-// ///
-// public static class GodotKeyMapper
-// {
-// private static readonly Dictionary KeyMap = new()
-// {
-// { "Left", Key.Left },
-// { "Right", Key.Right },
-// { "Up", Key.Up },
-// { "Down", Key.Down },
-// { "Space", Key.Space },
-// { "Enter", Key.Enter },
-// { "Escape", Key.Escape },
-// { "A", Key.A },
-// { "B", Key.B },
-// { "C", Key.C },
-// { "D", Key.D },
-// { "E", Key.E },
-// { "F", Key.F },
-// { "G", Key.G },
-// { "H", Key.H },
-// { "I", Key.I },
-// { "J", Key.J },
-// { "K", Key.K },
-// { "L", Key.L },
-// { "M", Key.M },
-// { "N", Key.N },
-// { "O", Key.O },
-// { "P", Key.P },
-// { "Q", Key.Q },
-// { "R", Key.R },
-// { "S", Key.S },
-// { "T", Key.T },
-// { "U", Key.U },
-// { "V", Key.V },
-// { "W", Key.W },
-// { "X", Key.X },
-// { "Y", Key.Y },
-// { "Z", Key.Z },
-// { "0", Key.Key0 },
-// { "1", Key.Key1 },
-// { "2", Key.Key2 },
-// { "3", Key.Key3 },
-// { "4", Key.Key4 },
-// { "5", Key.Key5 },
-// { "6", Key.Key6 },
-// { "7", Key.Key7 },
-// { "8", Key.Key8 },
-// { "9", Key.Key9 }
-// };
-//
-// private static readonly Dictionary MouseButtonMap = new()
-// {
-// { "LeftMouse", MouseButton.Left },
-// { "RightMouse", MouseButton.Right },
-// { "MiddleMouse", MouseButton.Middle }
-// };
-//
-// public static Key GetKeyFromString(string keyString)
-// {
-// return KeyMap.GetValueOrDefault(keyString, Key.None);
-// }
-//
-// public static MouseButton GetMouseButtonFromString(string mouseButtonString)
-// {
-// return MouseButtonMap.GetValueOrDefault(mouseButtonString, MouseButton.None);
-// }
-// }
\ No newline at end of file
diff --git a/GFramework.Godot/system/IInputSystem.cs b/GFramework.Godot/system/IInputSystem.cs
deleted file mode 100644
index 4e44727..0000000
--- a/GFramework.Godot/system/IInputSystem.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using GFramework.Core.system;
-
-namespace GFramework.Godot.system;
-
-///
-/// 输入系统接口,用于统一管理游戏中的输入操作和键位绑定
-///
-public interface IInputSystem : ISystem
-{
- ///
- /// 设置指定动作的按键绑定
- ///
- /// 动作名称
- /// 按键码
- void SetBinding(string actionName, string keyCode);
-
- ///
- /// 获取指定动作的按键绑定
- ///
- /// 动作名称
- /// 绑定的按键码
- string GetBinding(string actionName);
-
- ///
- /// 检查指定动作是否正在被执行
- ///
- /// 动作名称
- /// 如果动作正在执行则返回true,否则返回false
- bool IsActionPressed(string actionName);
-
- ///
- /// 检查指定动作是否刚刚开始执行
- ///
- /// 动作名称
- /// 如果动作刚刚开始执行则返回true,否则返回false
- bool IsActionJustPressed(string actionName);
-
- ///
- /// 检查指定动作是否刚刚停止执行
- ///
- /// 动作名称
- /// 如果动作刚刚停止执行则返回true,否则返回false
- bool IsActionJustReleased(string actionName);
-
- ///
- /// 添加输入动作
- ///
- /// 动作名称
- /// 默认按键绑定
- void AddAction(string actionName, string defaultKeyCode);
-
- ///
- /// 移除输入动作
- ///
- /// 动作名称
- void RemoveAction(string actionName);
-
- ///
- /// 保存输入配置到文件
- ///
- void SaveConfiguration();
-
- ///
- /// 从文件加载输入配置
- ///
- void LoadConfiguration();
-
- ///
- /// 更新输入系统状态,应在每帧调用
- ///
- /// 帧间隔时间
- void Update(double delta);
-}
\ No newline at end of file
diff --git a/GFramework.Godot/system/InputAction.cs b/GFramework.Godot/system/InputAction.cs
deleted file mode 100644
index f1cf934..0000000
--- a/GFramework.Godot/system/InputAction.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-namespace GFramework.Godot.system;
-
-///
-/// 输入动作类,表示游戏中的一种输入行为
-///
-public class InputAction
-{
- ///
- /// 动作名称
- ///
- public string Name { get; }
-
- ///
- /// 动作类型
- ///
- public InputActionType ActionType { get; }
-
- ///
- /// 默认按键绑定
- ///
- public string[] DefaultBindings { get; }
-
- ///
- /// 当前按键绑定
- ///
- public string[] CurrentBindings { get; private set; }
-
- ///
- /// 构造函数
- ///
- /// 动作名称
- /// 动作类型
- /// 默认按键绑定
- public InputAction(string name, InputActionType actionType, params string[] defaultBindings)
- {
- Name = name ?? throw new ArgumentNullException(nameof(name));
- ActionType = actionType;
- DefaultBindings = defaultBindings ?? throw new ArgumentNullException(nameof(defaultBindings));
- CurrentBindings = (string[])defaultBindings.Clone();
- }
-
- ///
- /// 重置为默认按键绑定
- ///
- public void ResetToDefault()
- {
- CurrentBindings = (string[])DefaultBindings.Clone();
- }
-
- ///
- /// 设置新的按键绑定
- ///
- /// 新的按键绑定
- public void SetBindings(params string[] bindings)
- {
- CurrentBindings = bindings ?? throw new ArgumentNullException(nameof(bindings));
- }
-}
-
-///
-/// 输入动作类型枚举
-///
-public enum InputActionType
-{
- ///
- /// 按钮类型,如跳跃、射击等
- ///
- Button,
-
- ///
- /// 轴类型,如移动、视角控制等
- ///
- Axis,
-
- ///
- /// 向量类型,如二维移动控制
- ///
- Vector
-}
\ No newline at end of file
diff --git a/GFramework.Godot/system/InputMap.cs b/GFramework.Godot/system/InputMap.cs
deleted file mode 100644
index 416656f..0000000
--- a/GFramework.Godot/system/InputMap.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-namespace GFramework.Godot.system;
-
-///
-/// 输入映射类,管理所有的输入动作及其绑定
-///
-public class InputMap
-{
- private readonly Dictionary _actions = new();
-
- ///
- /// 添加输入动作
- ///
- /// 输入动作
- public void AddAction(InputAction action)
- {
- _actions[action.Name] = action;
- }
-
- ///
- /// 移除输入动作
- ///
- /// 动作名称
- public void RemoveAction(string actionName)
- {
- _actions.Remove(actionName);
- }
-
- ///
- /// 获取输入动作
- ///
- /// 动作名称
- /// 输入动作,如果不存在则返回null
- public InputAction GetAction(string actionName)
- {
- return _actions.GetValueOrDefault(actionName);
- }
-
- ///
- /// 获取所有输入动作
- ///
- /// 输入动作列表
- public IEnumerable GetAllActions()
- {
- return _actions.Values;
- }
-
- ///
- /// 检查是否存在指定名称的动作
- ///
- /// 动作名称
- /// 存在返回true,否则返回false
- public bool ContainsAction(string actionName)
- {
- return _actions.ContainsKey(actionName);
- }
-
- ///
- /// 根据按键查找绑定的动作
- ///
- /// 按键码
- /// 绑定到该按键的所有动作
- public IEnumerable FindActionsByBinding(string keyCode)
- {
- return _actions.Values.Where(action =>
- action.CurrentBindings.Contains(keyCode));
- }
-}
\ No newline at end of file