Unity MyFramework 用法说明(二十七):使用 InputSystem 与 KeyMappingSystem 统一管理输入和快捷键
角色移动、技能快捷键、编辑器操作和界面关闭都需要读取输入。如果业务代码到处直接调用Input.GetKeyDown()按键规则、输入焦点和改键功能就会分散在不同系统中。MyFramework 使用InputSystem统一收集键盘、鼠标和触摸状态再通过KeyMappingSystem将具体按键映射为游戏行为。项目地址https://github.com/ZHOURUIH/MyFramework需要注意这里的InputSystem是 MyFramework 对UnityEngine.Input的封装不是 Unity 官方的 Input System Package。一、两个系统分别负责什么两个系统解决的问题不同InputSystem ├── 读取键盘状态 ├── 统一鼠标与触摸输入 ├── 识别单击和双击 ├── 监听固定快捷键 ├── 处理组合键 └── 区分场景输入与输入框输入 KeyMappingSystem ├── 将游戏行为映射到 KeyCode ├── 保存默认按键 ├── 修改当前按键 ├── 检测按键冲突 └── 提供用于界面显示的按键名称可以简单理解为InputSystem 负责“用户按了什么” KeyMappingSystem 负责“这个按键代表什么行为”二、为什么需要按键映射直接在移动逻辑中判断if (Input.GetKeyDown(KeyCode.W)) { moveUp(); }意味着“向上移动”这个行为和W键永久绑定。玩家改成方向键后需要修改所有使用W的代码。更合理的方式是先定义行为 IDpublic static class KEY_MAPPING { public const int MOVE_UP 1; public const int MOVE_DOWN 2; public const int ATTACK 3; public const int OPEN_PACK 4; }业务系统只判断行为if (mKeyMappingSystem.isMappingKeyDown( KEY_MAPPING.MOVE_UP)) { moveUp(); }至于“向上移动”当前对应W还是方向键由KeyMappingSystem决定。三、注册默认快捷键游戏初始化时注册行为和默认按键using UnityEngine; using static FrameBaseHotFix; public static class GameKeyMapping { public static void init() { registe( KEY_MAPPING.MOVE_UP, KeyCode.W, 向上移动); registe( KEY_MAPPING.MOVE_DOWN, KeyCode.S, 向下移动); registe( KEY_MAPPING.ATTACK, KeyCode.Space, 普通攻击); registe( KEY_MAPPING.OPEN_PACK, KeyCode.B, 打开背包); } private static void registe( int mapping, KeyCode key, string actionName) { if (!mKeyMappingSystem.setKeyMapping( mapping, key, actionName)) { return; } mKeyMappingSystem.setDefaultKeyMapping( mapping, key); } }其中保存了三类信息Mapping ID 表示游戏行为 当前按键 表示玩家目前使用的按键 默认按键 用于恢复默认设置actionName主要用于快捷键设置界面例如显示向上移动 W 普通攻击 Space 打开背包 B四、区分按下瞬间和持续按住只在按下的这一帧触发if (mKeyMappingSystem.isMappingKeyCurrentDown( KEY_MAPPING.OPEN_PACK)) { LT.LOADUIPack(); }适合打开界面 释放一次技能 确认操作 拾取物品持续按住期间一直返回trueif (mKeyMappingSystem.isMappingKeyDown( KEY_MAPPING.MOVE_UP)) { moveUp(); }适合角色移动 摄像机移动 持续蓄力 连续操作两者最终会调用InputSystempublic bool isMappingKeyCurrentDown(int mapping) { return mInputSystem.isKeyCurrentDown( getKeyMapping(mapping), FOCUS_MASK.SCENE); } public bool isMappingKeyDown(int mapping) { return mInputSystem.isKeyDown( getKeyMapping(mapping), FOCUS_MASK.SCENE); }所以映射按键默认只处理场景输入不会在输入框中输入文字时误触发游戏快捷键。五、运行时修改按键玩家在设置界面中按下一个新键后可以重新设置映射protected bool changeKeyMapping( int mapping, KeyCode newKey) { if (!mKeyMappingSystem.setKeyMapping( mapping, newKey)) { return false; } // 在这里由应用层保存玩家的快捷键配置 return true; }setKeyMapping()会检查新按键是否已经被其他行为占用if (key ! KeyCode.None mKeyMapping.containsValue( item item.mKey key item.mMappingID ! mappingID)) { logError(有冲突的按键: key); return false; }例如B已经用于打开背包再把它设置为普通攻击时接口会返回false。框架负责映射和冲突检测玩家按键配置的持久化则由应用层处理。六、显示当前按键名称获取某个行为当前绑定的按键KeyCode key mKeyMappingSystem.getKeyMapping( KEY_MAPPING.OPEN_PACK);获取用于界面显示的名称string keyName mKeyMappingSystem.getKeyMappingName( KEY_MAPPING.OPEN_PACK);获取行为名称string actionName mKeyMappingSystem.getKeyMappingActionName( KEY_MAPPING.OPEN_PACK);快捷键设置界面可以直接显示mActionText.setText(actionName); mKeyText.setText(keyName);框架已经为常见按键准备了显示名称例如KeyCode.Space → Space KeyCode.Delete → Del KeyCode.PageUp → PgUp KeyCode.UpArrow → ↑ KeyCode.Keypad1 → Num1恢复默认设置时可以读取KeyCode defaultKey mKeyMappingSystem.getDefaultMappingKey(mapping);再重新调用setKeyMapping()。七、固定快捷键不需要建立映射并不是所有按键都允许玩家修改。例如Esc 关闭界面 Ctrl S 保存UGC作品 F1 切换调试信息这类固定或临时快捷键可以直接通过InputSystem注册public class UGCShortcutSystem : FrameSystem { public override void init() { base.init(); mInputSystem.listenKeyCurrentDown( KeyCode.S, onSave, this, COMBINATION_KEY.CTRL); mInputSystem.listenKeyCurrentDown( KeyCode.Escape, onEscape, this); } public override void destroy() { mInputSystem?.unlistenKey(this); base.destroy(); } protected void onSave() { saveUGCContent(); } protected void onEscape() { closeCurrentPanel(); } protected void saveUGCContent() { } protected void closeCurrentPanel() { } }监听时需要传入监听者this销毁时可以一次性移除该监听者注册的所有快捷键mInputSystem.unlistenKey(this);避免对象销毁后旧回调继续执行。八、组合键如何处理框架支持Ctrl Shift Alt例如监听Ctrl Shift SmInputSystem.listenKeyCurrentDown( KeyCode.S, onSaveAs, this, COMBINATION_KEY.CTRL | COMBINATION_KEY.SHIFT);InputSystem每帧统计当前组合键状态COMBINATION_KEY combination COMBINATION_KEY.NONE; combination | isAnyKeyDown( KeyCode.LeftControl, KeyCode.RightControl) ? COMBINATION_KEY.CTRL : COMBINATION_KEY.NONE;然后与监听信息进行比较if (info.mCombinationKey combination) { info.mCallback?.Invoke(); }这里使用的是完全匹配。注册Ctrl S后如果当前实际按下的是Ctrl Shift S不会触发这条监听。九、输入框为什么不会触发场景快捷键InputSystem保存了当前输入焦点protected int mFocusMask;每帧检查已经注册的输入框bool inputting false; foreach (IInputField item in mInputFieldList) { if (item.isVisible() item.isFocused()) { inputting true; break; } } setMask( inputting ? FOCUS_MASK.UI : FOCUS_MASK.SCENE);查询按键时会检查掩码public bool isKeyCurrentDown( KeyCode key, FOCUS_MASK mask FOCUS_MASK.SCENE) { return mEnableKey Input.GetKeyDown(key) hasMask(mask); }因此当玩家正在聊天输入框中输入B时不会同时打开背包。这比每个业务系统分别判断“当前是否正在输入”更加可靠。十、统一鼠标和触摸输入InputSystem将鼠标按键和移动端触点统一保存为SafeDictionaryint, TouchPoint获取本帧完成的单击if (mInputSystem.getTouchClick( out TouchPoint touch)) { Vector3 position touch.getCurPosition(); }获取双击if (mInputSystem.getTouchDoubleClick( out TouchPoint touch)) { Vector3 position touch.getCurPosition(); }获取触点移动量TouchPoint point mInputSystem.getTouchPoint(pointerID); Vector3 moveDelta point?.getMoveDelta() ?? Vector3.zero;TouchPoint会记录按下位置 当前位置 上一帧位置 本帧移动量 按下与抬起时间 是否单击 是否双击 是否持续按下桌面端鼠标左、中、右键也会被当作固定触点因此部分点击逻辑不需要分别编写鼠标版和触屏版。十一、InputSystem 的每帧流程InputSystem.update()的主要流程是读取鼠标或触屏按下、抬起 ↓ 更新所有 TouchPoint 的位置 ↓ 根据时间和距离识别单击、双击 ↓ 检查当前是否有输入框获得焦点 ↓ 设置 UI 或 SCENE 输入掩码 ↓ 收集本帧按下和抬起的键 ↓ 计算 Ctrl、Shift、Alt 状态 ↓ 分发固定快捷键监听lateUpdate()再清除当前帧状态CurrentDown CurrentUp Click DoubleClick所以这类状态只在当前帧有效业务系统应当在正常更新阶段读取。十二、总结MyFramework 将输入分为两个层次InputSystem 统一采集键盘、鼠标、触摸和输入焦点 KeyMappingSystem 把具体按键转换为可配置的游戏行为使用原则可以概括为玩家可以修改的游戏操作 使用 KeyMappingSystem 固定的系统或调试快捷键 使用 listenKeyCurrentDown 持续操作 使用 isMappingKeyDown 单次操作 使用 isMappingKeyCurrentDown 对象销毁 调用 unlistenKey 输入框正在输入 由 FOCUS_MASK 自动屏蔽场景快捷键这样角色移动、技能快捷键、UGC 编辑器操作和界面输入可以使用同一套输入状态同时保持游戏行为与具体按键之间的独立。

相关新闻

SpringBoot+Vue电影购票系统开发实战与优化

SpringBoot+Vue电影购票系统开发实战与优化

1. 项目概述"基于SpringBoot和Vue电影购票管理系统的设计与实现"是一个典型的现代前后端分离架构的商业应用项目。这个系统旨在为电影院线提供一套完整的在线购票解决方案,包含用户端购票界面和管理端后台管理功能。作为全栈开发项目,它完美结…

2026/8/4 17:01:43 阅读更多 →
AI内容降重工具对比:免费与付费效果实测

AI内容降重工具对比:免费与付费效果实测

1. 项目概述最近在内容创作圈子里,关于AI生成内容检测和降AI率的讨论越来越热。作为一个长期关注内容原创性的创作者,我花了三周时间系统测试了市面上主流的12款降AI率工具(6款免费,6款付费),用真实数据来回…

2026/8/4 17:01:43 阅读更多 →
VisualCppRedist AIO实战指南:自动化解决Windows运行库兼容性问题的完整方案

VisualCppRedist AIO实战指南:自动化解决Windows运行库兼容性问题的完整方案

VisualCppRedist AIO实战指南:自动化解决Windows运行库兼容性问题的完整方案 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist VisualCppRedist AIO是一…

2026/8/4 17:01:43 阅读更多 →

最新新闻

《碧蓝幻想Relink》DLC无尽黄昏高效开荒指南:资源循环与战力构建

《碧蓝幻想Relink》DLC无尽黄昏高效开荒指南:资源循环与战力构建

如果你最近在《碧蓝幻想Relink》的DLC“无尽黄昏”里,感觉开荒压力山大,刷得又累又迷茫,那这篇文章就是为你准备的。很多玩家拿到新内容,第一反应就是冲进去“肝”,结果发现怪物血厚攻高,自己刮痧半天&…

2026/8/4 17:49:07 阅读更多 →
SSM+Vue抗疫物资管理系统毕业设计指南

SSM+Vue抗疫物资管理系统毕业设计指南

1. 项目背景与核心价值 2026届计算机相关专业毕业生面临的毕业设计选题中,"抗疫物资管理系统"依然是个值得深入挖掘的方向。这个选题结合了SSM(SpringSpringMVCMyBatis)和Vue.js两大主流技术栈,具有鲜明的时代特征和实用…

2026/8/4 17:49:06 阅读更多 →
【Bug已解决】GPTNeo Error Attempting to Generate Text 解决方案

【Bug已解决】GPTNeo Error Attempting to Generate Text 解决方案

【Bug已解决】GPTNeo Error Attempting to Generate Text 解决方案 一、现象长什么样 用 GPT-Neo(EleutherAI 的 GPT-Neo,如 EleutherAI/gpt-neo-125M)调用 model.generate(...) 时,常见几种报错: ValueError: Cann…

2026/8/4 17:49:06 阅读更多 →
CefFlashBrowser:终极Flash浏览器解决方案,免费畅玩经典游戏

CefFlashBrowser:终极Flash浏览器解决方案,免费畅玩经典游戏

CefFlashBrowser:终极Flash浏览器解决方案,免费畅玩经典游戏 【免费下载链接】CefFlashBrowser Flash浏览器 / Flash Browser 项目地址: https://gitcode.com/gh_mirrors/ce/CefFlashBrowser 在Flash技术正式退役后,无数经典游戏和网页…

2026/8/4 17:48:06 阅读更多 →
外包高薪与大厂正编的职业选择分析

外包高薪与大厂正编的职业选择分析

1. 职业选择的两难困境:外包高薪与大厂编制的博弈最近在职场论坛上看到一个引发热议的话题:一位从业者同时拿到了两个offer,一个是外包岗位年薪55万,另一个是大厂正编岗位年薪28万。这个看似简单的选择题背后,实际上折…

2026/8/4 17:48:06 阅读更多 →
基于tr内网穿透工具与文件管理系统的私有云盘搭建研究

基于tr内网穿透工具与文件管理系统的私有云盘搭建研究

1. 引言 1.1 研究背景 随着互联网技术的飞速发展,网络应用在各个领域中的重要性日益凸显。特别是在远程办公、服务器维护以及智能家居等场景中,内网穿透技术作为一种能够实现外部网络对内部网络资源访问的关键技术,逐渐成为研究热点。内网穿透…

2026/8/4 17:48:06 阅读更多 →

日新闻

AI Agent白手起家26: 使用标准事件驱动大模型实践

AI Agent白手起家26: 使用标准事件驱动大模型实践

纲要 练习目标:掌握大模型标准事件的调用回顾 LangChain 中的核心标准事件 invokestreambatchastream_eventswith_structured_output 环境准备实战代码:多种事件调用对比 同步调用与流式输出批量处理异步事件流监听结构化输出 运行说明与预期结果总结与扩…

2026/8/4 0:00:40 阅读更多 →
dealsea是什么?跨境卖家必知的美国deal站入门指南

dealsea是什么?跨境卖家必知的美国deal站入门指南

说实话,第一次听说美国这个老牌折扣网站的跨境卖家,十个有八个会问同一个问题:这个平台到底是干嘛的?我见过一个做家居出口的朋友,他在亚马逊上月销二十万美金,却从来没用过它。我给他看了首页——一屏一屏…

2026/8/4 0:01:40 阅读更多 →
清华大学重磅EST:植物自导电闪蒸焦耳热600°C/2600°C两步法!稀土超积累植物秒级转化为CeO₂-石墨烯电催化剂!

清华大学重磅EST:植物自导电闪蒸焦耳热600°C/2600°C两步法!稀土超积累植物秒级转化为CeO₂-石墨烯电催化剂!

通讯作者:邓兵、刘建国通讯单位:清华大学DOI:https://doi.org/10.1021/acs.est.6c00603研究背景稀土元素(REEs)是清洁能源技术与电子器件不可或缺的核心原料,然而传统提取方式依赖能耗高、排放大的采矿与强…

2026/8/4 0:01:40 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/4 13:24:41 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/4 11:41:39 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/4 5:26:40 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →