Unity 按键输入系统(一)

2023-11-13

           这段时间制作了游戏内的操作系统,主要制作的原因是,在游戏内很多按键是公用的,但是不同位置的处理逻辑不同,比如在最外层界面上,可以使用ESC打开菜单,但是在二级界面里,使用ESC是返回上个界面,如果要使用判断制作的话,会产生很强的耦合性,要在很多位置加入判断逻辑,所以制作了这套按键,先写出代码,下一篇会介绍怎么使用。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class KeystorkeLayer
{
    public string registerName;
    public Dictionary<KeyCode, Util.NoneParamFunction> keystrokeDict = new Dictionary<KeyCode, Util.NoneParamFunction>();
    public Dictionary<int, Util.NoneParamFunction> mouseDict = new Dictionary<int, Util.NoneParamFunction>();
    public Dictionary<string, List<Util.NoneParamFunction>> axisDict = new Dictionary<string, List<Util.NoneParamFunction>>();

    public HashSet<KeyCode> keyDisableHashSet = new HashSet<KeyCode>();
    public HashSet<int> mouseDisableHashSet = new HashSet<int>();
    public HashSet<string> axisDisableHashSet = new HashSet<string>();

    public int axisCheckFrameCount = 1;
    public bool forceTop;

    public KeystorkeLayer(string registerName, bool forceTop)
    {
        this.registerName = registerName;
        this.forceTop = forceTop;
    }

    public void RegisterKeys(List<KeyCode> list, Util.NoneParamFunction callback)
    {
        if (list == null || list.Count <= 0)
        {
            return;
        }
        for (int i = 0; i < list.Count; i++)
        {
            RegisterKey(list[i], callback);
        }
    }

    public void UnRegisterKeys(List<KeyCode> list)
    {
        if (list == null || list.Count <= 0)
        {
            return;
        }
        for (int i = 0; i < list.Count; i++)
        {
            UnRegisterKey(list[i]);
        }
    }

    public void RegisterKey(KeyCode key, Util.NoneParamFunction callback)
    {
        keystrokeDict[key] = callback;
    }

    public void UnRegisterKey(KeyCode key)
    {
        if (!keystrokeDict.ContainsKey(key))
        {
            Debug.LogError("Error Key");
            return;
        }
        keystrokeDict.Remove(key);
    }

    public void SetKeyEnableState(KeyCode key, bool enable)
    {
        if (enable)
        {
            keyDisableHashSet.Remove(key);
        }
        else
        {
            keyDisableHashSet.Add(key);
        }
    }

    public void RegisterMouse(int mouseIndex, Util.NoneParamFunction callback)
    {
        mouseDict[mouseIndex] = callback;
    }

    public void UnRegisterMouse(int mouseIndex)
    {
        if (!mouseDict.ContainsKey(mouseIndex))
        {
            Debug.LogError("Error Mouse");
            return;
        }
        mouseDict.Remove(mouseIndex);
    }

    public void SetMouseEnableState(int mouseIndex, bool enable)
    {
        if (enable)
        {
            mouseDisableHashSet.Remove(mouseIndex);
        }
        else
        {
            mouseDisableHashSet.Add(mouseIndex);
        }
    }

    public void RegisterAixs(string axisName, Util.NoneParamFunction firstCallback, Util.NoneParamFunction secondCallback)
    {
        axisDict[axisName] = new List<Util.NoneParamFunction>();
        axisDict[axisName].Add(firstCallback);
        axisDict[axisName].Add(secondCallback);
    }

    public void UnRegisterAixs(string axisName)
    {
        if(!axisDict.ContainsKey(axisName))
        {
            Debug.LogError("Error Axis");
            return;
        }
        axisDict.Remove(axisName);
    }

    public void SetAxisEnableState(string axisName, bool enable)
    {
        if (enable)
        {
            axisDisableHashSet.Remove(axisName);
        }
        else
        {
            axisDisableHashSet.Add(axisName);
        }
    }


    public void RemoveKeystorkeLayer()
    {
        for (int i = 0; i < QA.keystrokeMan.keystorkeLayerStack.Count; i++)
        {
            if (QA.keystrokeMan.keystorkeLayerStack.ElementAt(i) == this)
            {
                Stack<KeystorkeLayer> tempStack = new Stack<KeystorkeLayer>();
                for (int j = 0; j < i; j++)
                {
                    tempStack.Push(QA.keystrokeMan.keystorkeLayerStack.Pop());
                }
                QA.keystrokeMan.keystorkeLayerStack.Pop();
                while (tempStack.Count > 0)
                {
                    QA.keystrokeMan.keystorkeLayerStack.Push(tempStack.Pop());
                }
            }
        }
        // 从Stack中删除层时,也从exitLayerStack中删除
        if (QA.keystrokeMan.exitLayerStack.Contains(this))
        {
            for (int i = 0; i < QA.keystrokeMan.exitLayerStack.Count; i++)
            {
                if (QA.keystrokeMan.exitLayerStack.ElementAt(i) == this)
                {
                    Stack<KeystorkeLayer> tempStack = new Stack<KeystorkeLayer>();
                    for (int j = 0; j < i; j++)
                    {
                        tempStack.Push(QA.keystrokeMan.exitLayerStack.Pop());
                    }
                    QA.keystrokeMan.exitLayerStack.Pop();
                    while (tempStack.Count > 0)
                    {
                        QA.keystrokeMan.exitLayerStack.Push(tempStack.Pop());
                    }
                }
            }
        }
        Debug.LogError("PopTopKeystorkeLayer......." + registerName);
    }
}

public class KeystrokeManager
{
    public Stack<KeystorkeLayer> keystorkeLayerStack = new Stack<KeystorkeLayer>();
    public Stack<KeystorkeLayer> exitLayerStack = new Stack<KeystorkeLayer>();

    public KeystorkeLayer PushNewKeystorkeLayer(string registerName, bool forceTop = false)
    {
        registerName = registerName.Replace("(Clone)", "");
        Debug.LogError("PushNewKeystorkeLayer......." + registerName);
        KeystorkeLayer layer = new KeystorkeLayer(registerName, forceTop);
        // 检测顶层是否强制置顶
        KeystorkeLayer addLayer = null;
        if (keystorkeLayerStack.Count > 0 && keystorkeLayerStack.Peek().forceTop)
        {
            addLayer = keystorkeLayerStack.Pop();
        }
        keystorkeLayerStack.Push(layer);
        if (addLayer != null)
        {
            keystorkeLayerStack.Push(addLayer);
        }
        return layer;
    }

    public void PopTopKeystorkeLayer()
    {
        if (keystorkeLayerStack.Count <= 0)
        {
            Debug.LogError("No Layer Exist");
            return;
        }
        KeystorkeLayer layer = keystorkeLayerStack.Pop();

        // 从Stack中删除层时,也从exitLayerStack中删除
        if (exitLayerStack.Contains(layer))
        {
            for (int i = 0; i < exitLayerStack.Count; i++)
            {
                if (exitLayerStack.ElementAt(i) == layer)
                {
                    Stack<KeystorkeLayer> tempStack = new Stack<KeystorkeLayer>();
                    for (int j = 0; j < i; j++)
                    {
                        tempStack.Push(exitLayerStack.Pop());
                    }
                    exitLayerStack.Pop();
                    while (tempStack.Count > 0)
                    {
                        exitLayerStack.Push(tempStack.Pop());
                    }
                }
            }
        }

        Debug.LogError("PopTopKeystorkeLayer......." + layer.registerName);
    }

    public void RegisterKeys(List<KeyCode> list, Util.NoneParamFunction callback)
    {
        if (list == null || list.Count <= 0)
        {
            return;
        }
        for (int i = 0; i < list.Count; i++)
        {
            RegisterKey(list[i], callback);
        }
    }

    public void RegisterKey(KeyCode key, Util.NoneParamFunction callback)
    {
        keystorkeLayerStack.Peek().keystrokeDict[key] = callback;
    }

    public void UnRegisterKey(KeyCode key)
    {
        if (!keystorkeLayerStack.Peek().keystrokeDict.ContainsKey(key))
        {
            Debug.LogError("Error Key");
            return;
        }
        keystorkeLayerStack.Peek().keystrokeDict.Remove(key);
    }

    public void SetKeyEnableState(KeyCode key, bool enable)
    {
        if (enable)
        {
            keystorkeLayerStack.Peek().keyDisableHashSet.Remove(key);
        }
        else
        {
            keystorkeLayerStack.Peek().keyDisableHashSet.Add(key);
        }
    }

    public void RegisterMouse(int mouseIndex, Util.NoneParamFunction callback)
    {
        keystorkeLayerStack.Peek().mouseDict[mouseIndex] = callback;
    }

    public void UnRegisterMouse(int mouseIndex)
    {
        if (!keystorkeLayerStack.Peek().mouseDict.ContainsKey(mouseIndex))
        {
            Debug.LogError("Error Mouse");
            return;
        }
        keystorkeLayerStack.Peek().mouseDict.Remove(mouseIndex);
    }

    public void SetMouseEnableState(int mouseIndex, bool enable)
    {
        if (enable)
        {
            keystorkeLayerStack.Peek().mouseDisableHashSet.Remove(mouseIndex);
        }
        else
        {
            keystorkeLayerStack.Peek().mouseDisableHashSet.Add(mouseIndex);
        }
    }

    [System.Obsolete("尽量不要用这个方法,无法通过控制顺序来控制按键时再使用")]
    public void SetKeyEnableState(int index, KeyCode key, bool enable)
    {
        if (index > keystorkeLayerStack.Count - 1 || index < 0)
        {
            Debug.LogError("Error Index");
        }
        var layer = keystorkeLayerStack.ElementAt(index);
        if (enable)
        {
            layer.keyDisableHashSet.Remove(key);
        }
        else
        {
            layer.keyDisableHashSet.Add(key);
        }
    }

    public void CheckInput()
    {
        if (keystorkeLayerStack.Count <= 0)
        {
            return;
        }

        var layer = keystorkeLayerStack.Peek();
        if (Input.anyKeyDown)
        {
            // 键盘
            foreach (var kv in layer.keystrokeDict)
            {
                if (Input.GetKeyDown(kv.Key) && !layer.keyDisableHashSet.Contains(kv.Key))
                {
                    Debug.LogError(layer.registerName + " - " + kv.Key + "!!!!!!!!!!!!!!!!!!!!!!!");
                    kv.Value?.Invoke();
                    return;
                }
            }
        }


        if (Input.GetMouseButtonDown(0) && layer.mouseDict.ContainsKey(0) && !layer.mouseDisableHashSet.Contains(0))
        {
            layer.mouseDict[0]?.Invoke();
            return;
        }

        if (Input.GetMouseButtonDown(1) && layer.mouseDict.ContainsKey(1) && !layer.mouseDisableHashSet.Contains(1))
        {
            layer.mouseDict[1]?.Invoke();
            return;
        }

        // 沒有處理鎖住的問題
        if (Time.frameCount % layer.axisCheckFrameCount == 0)
        {
            // 每五帧执行一次
            foreach (var kv in layer.axisDict)
            {
                float axisValue = Input.GetAxisRaw(kv.Key);
                if (!Mathf.Approximately(axisValue, 0))
                {
                    if (!layer.axisDisableHashSet.Contains(kv.Key))
                    {
                        kv.Value[axisValue > 0 ? 0 : 1]?.Invoke();
                        layer.axisDisableHashSet.Add(kv.Key);
                        return;
                    }
                } else
                {
                    layer.axisDisableHashSet.Remove(kv.Key);
                }
            }
        }

#if UNITY_EDITOR
        if (Input.GetKeyDown(KeyCode.L))
        {
            Debug.Log("Show Layer Info : " + layer.registerName);
            Debug.LogError("=========================");
            foreach (var kv in layer.keystrokeDict)
            {
                Debug.Log(kv.Key + " ---- enable : " + !layer.keyDisableHashSet.Contains(kv.Key));
            }
            foreach (var kv in layer.mouseDict)
            {
                Debug.Log(kv.Key + " ---- enable : " + !layer.mouseDisableHashSet.Contains(kv.Key));
            }
            Debug.Log("=========================");
        }

        if (Input.GetKeyDown(KeyCode.K))
        {
            var s = QA.interfaceUIMan.activePageStack.ToArray();
            for (int i = 0; i < s.Length; i++)
            {
                Debug.Log(s[i].Key);
            }
        }
#endif
    }

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Unity 按键输入系统(一) 的相关文章

  • 在C语言中使用“void”

    我很困惑为什么我们需要通过void转换为 C 函数 int f void return 0 versus int f return 0 什么是正确的做法以及为什么 In C int f 是一种老式的声明 它说f需要固定但未指定数量和类型的参
  • 具有子列表属性映射问题的自动映射器

    我有以下型号 Models public class Dish Required public Int64 ID get set Required public string Name get set Required public str
  • 进程何时获得 SIGABRT(信号 6)?

    C 中进程获得 SIGABRT 的场景有哪些 该信号是否始终来自进程内部 或者该信号可以从一个进程发送到另一个进程吗 有没有办法识别哪个进程正在发送该信号 abort 向调用进程发送SIGABRT信号 就是这样abort 基本上有效 abo
  • 向 ExpandoObject 添加方法时,“关键字 'this' 在静态属性、静态方法或静态字段初始值设定项中无效”

    我尝试向 ExpandoObject 添加一个动态方法 该方法将返回属性 动态添加 给它 但它总是给我错误 我在这里做错了什么吗 using System using System Collections Generic using Sys
  • 如何在 Android NDK 中创建新的 NativeWindow 而无需 Android 操作系统源代码?

    我想编译一个 Android OpenGL 控制台应用程序 您可以直接从控制台启动 Android x86 运行 或者从 Android x86 GUI 内的 Android 终端应用程序运行 这个帖子 如何在 Android NDK 中创
  • 构造函数中显式关键字的使用

    我试图了解 C 中显式关键字的用法 并查看了这个问题C 中的explicit关键字是什么意思 https stackoverflow com questions 121162 但是 那里列出的示例 实际上是前两个答案 对于用法并不是很清楚
  • 对齐 GridView 中的行值

    我需要在 asp net 3 5 中右对齐 gridview 列中的值 我怎样才能做到这一点
  • POCO HTTPSClientSession 发送请求时遇到问题 - 证书验证失败

    我正在尝试使用 POCO 库编写一个向服务器发出 HTTPS 请求的程序 出于测试目的 我正在连接到具有自签名证书的服务器 并且我希望允许客户端进行连接 为了允许这种情况发生 我尝试安装InvalidCertificateHandler这是
  • 从多个类访问串行端口

    我正在尝试使用串行端口在 arduino 和 C 程序之间进行通信 我对 C 编程有点陌生 该程序有多种用户控制形式 每一个都需要访问串口来发送数据 我需要做的就是从每个类的主窗体中写入串行端口 我了解如何设置和写入串行端口 这是我的 Fo
  • 暂停下载线程

    我正在用 C 编写一个非常简单的批量下载程序 该程序读取要下载的 URL 的 txt 文件 我已经设置了一个全局线程和委托来更新 GUI 按下 开始 按钮即可创建并启动该线程 我想要做的是有一个 暂停 按钮 使我能够暂停下载 直到点击 恢复
  • 检查算术运算中的溢出情况[重复]

    这个问题在这里已经有答案了 可能的重复 检测 C C 中整数溢出的最佳方法 https stackoverflow com questions 199333 best way to detect integer overflow in c
  • 如何识别 WPF 文本框中的 ValidationError 工具提示位置

    我添加了一个箭头来指示工具提示中的文本框 当文本框远离屏幕边缘时 这非常有效 但是当它靠近屏幕边缘时 工具提示位置发生变化 箭头显示在左侧 Here is the Image Correct as expected since TextBo
  • 在非活动联合成员上使用“std::addressof”是否定义明确[重复]

    这个问题在这里已经有答案了 下面的代码是尝试实现constexpr的版本offsetof在 C 11 中 它可以在 gcc 7 2 0 和 clang 5 0 0 中编译 这取决于申请std addressof工会非活跃成员的成员 这是明确
  • 将构建日期放入“关于”框中

    我有一个带有 关于 框的 C WinForms 应用程序 我使用以下方法将版本号放入 关于 框中 FileVersionInfo GetVersionInfo Assembly GetExecutingAssembly Location F
  • 如何挤出平面 2D 网格并赋予其深度

    我有一组共面 连接的三角形 即二维网格 现在我需要将其在 z 轴上挤出几个单位 网格由一组顶点定义 渲染器通过与三角形数组匹配来理解这些顶点 网格示例 顶点 0 0 0 10 0 0 10 10 0 0 10 0 所以这里我们有一个二维正方
  • 是否可以有一个 out ParameterExpression?

    我想定义一个 Lambda 表达式out范围 有可能做到吗 下面是我尝试过的 C Net 4 0 控制台应用程序的代码片段 正如您在 procedure25 中看到的 我可以使用 lambda 表达式来定义具有输出参数的委托 但是 当我想使
  • 什么是 __declspec 以及何时需要使用它?

    我见过这样的例子 declspec在我正在阅读的代码中 它是什么 我什么时候需要使用这个构造 这是 Microsoft 对 C 语言的特定扩展 它允许您使用存储类信息来赋予类型或函数属性 文档 declspec C https learn
  • 运算符“==”不能应用于“int”和“string”类型的操作数

    我正在编写一个程序 我想到了一个数字 然后计算机猜测了它 我一边尝试一边测试它 但我不断收到不应该出现的错误 错误是主题标题 我使用 Int Parse 来转换我的字符串 但我不知道为什么会收到错误 我知道它说 不能与整数一起使用 但我在网
  • 用于 C# XNA 的 Javascript(或类似)游戏脚本

    最近我准备用 XNA C 开发另一个游戏 上次我在 XNA C 中开发游戏时 遇到了必须向游戏中添加地图和可自定义数据的问题 每次我想添加新内容或更改游戏角色的某些值或其他内容时 我都必须重建整个游戏或其他内容 这可能需要相当长的时间 有没
  • 错误:无效使用不完整类型“类 Move”/未定义对 Move::NONE 的引用

    拜托 我不知道为什么这个简单的代码被拒绝 它给了我 2 个编译错误 请帮帮我 I use 代码 块 20 03 我的编译器是GNU GCC 移动 hpp class Move public Move Move int int public

随机推荐

  • Android网络开源库-Retrofit(二) 文件上传、下载及进度监听

    1 写在前面的话 首先说明 我还没太搞懂retrofit 目前 这篇博客只能给出这几个内容 文件上传 文件下载 文件下载的进度监听 还有这两点没弄好 多文件一次上传 批量上传 文件上传进度监听 当前使用版本 compile com squa
  • 使用element UI的日期选择器,默认显示当天日期及7天前日期

    方法一 采用选择器 type datetimerange 默认获取内容为时间戳
  • 毕业设计-基于机器视觉的路面裂缝检测装置-OpenCV

    目录 前言 课题背景和意义 实现技术思路 一 系统架构及工作原理 二 图像传输和处置 三 裂缝检测 实现效果图样例 最后 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业设计耗费大量精力
  • oracle驱动重启吗,Troubleshooting for oracle

    本文总结与归纳了平常遇到的一些关于Oracle 18c的错误以及处理方法 会不定期的进行更新 1 dbca Fails With PRCR 1006 PRCR 1071 CRS 2566 这里的asm环境使用了Oracle ASM Filt
  • BGP基础实验(4)联邦划分

    目录 前言 一 实验拓扑图 二 实验目的 三 实验配置 1 路由器声明BGP进程 2 普通EBGP邻居建立 3 联邦IBGP邻居建立 4 联邦EBGP邻居建立 四 实验观测 五 实验总结 前言 网盘资源 BGP基础实验 联邦划分 zip 蓝
  • Linux01-虚拟机安装(VMware15+CentOS7)

    一 虚拟机介绍 虚拟机 Virtual Machine 指通过软件模拟的具有完整硬件系统功能的 运行在一个完全隔离环境中的完整计算机系统 在实体计算机中能够完成的工作在虚拟机中都能够实现 在计算机中创建虚拟机时 需要将实体机的部分硬盘和内存
  • 使用百度AI开放平台进行车牌识别

    文章目录 百度AI开放平台车牌识别使用 1 产生token 2 车牌识别 3 解析结果 参考 本文介绍了如何使用百度AI开放平台获取token 以及如何调用百度API接口 请求车牌识别 以及对结果进行解析 并根据百度返回的坐标值画出车牌所在
  • 使用Jasmine在Angular中测试组件:第1部分

    您将要创造的 测试驱动开发是一种编程实践 已由地球上每个开发人员社区宣讲和推广 但这是开发人员在学习新框架时经常忽略的例程 从第一天开始编写单元测试 将帮助您编写更好的代码 轻松发现错误并维护更好的开发工作流程 Angular中的测试驱动开
  • 六级单词词汇表(有注音)

    英语六级备考词汇表 abnormal b n m l a 不正常的 变态的 abolish b li vt 废除 取消 abrupt br pt a 突然的 意外的 唐突的 absurd b s d a 不合理的 荒唐的 abundance
  • python-16进制字符串和16进制数字转换

    0xa1 0x09 0x1c 0xef gt a1 09 1c ef b xa1 x09 x1c xef hex a1091cef a1 09 1c ef gt 0xa1 0x09 0x1c 0xef bytes fromhex a1091
  • 使用@Id时主键生成策略:TABLE、SEQUENCE、IDENTITY、AUTO

    主键生成策略 GenerationType TABLE GenerationType SEQUENCE GenerationType IDENTITY GenerationType AUTO TABLE 使用一个特定的数据库表格来保存主键
  • 《UML用户指南第二版》再次温读笔记(一)(downmoon)

    前言 最近 花点时间重读 也不知道是第几遍了 UML用户指南第二版 这本书 感觉虽然对WEB程序开发而言 UML的应用是一个极大的挑战 然而 其中蕴含的基本原理和指导性却是历久弥新 耐人回味 在此 特地摘录了部分让邀月留下印象的章节 以作备
  • eclipse里打开图片文件乱码解决方案

    从eclipse中打开工程文件下的图片文件显示乱码 原因是你电脑系统上没有设置图片的默认打开方式 或者是图片的默认打开方式与eclipse不兼容
  • 原始值和引用值

    ECMAScript 变量可以包含两种不同类型的数据 原始值和引用值 原始值就是简单数据类型 引用值则是由多个值构成的对象 原始值 引用值 原始值包括 Undefined Null Boolean Number String Symbol和
  • 【GAN 04】可解释性GAN

    本文是对http www seeprettyface com research notes html的学习笔记 不想让GANs随机生成图片 希望通过控制输入的参数去生成特定的图片 例如 在手写数字图片的生成中 希望通过输入 控制数字 高度以
  • Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Interop.E

    前段时间做了个将Txt中数据导出到Excel中的C 小应用程序 一直都运行很好的 今天突然有同事安装时 报如下错 Exception Text System InvalidCastException Unable to cast COM o
  • android横竖屏切换、键盘推出状态改变的处理

    背景介绍 在编写android小应用的时候 碰到了这样的一个问题 当推开手机的实体键盘时 屏幕由竖屏转换为横屏 此时应用程序的显示界面 Activity 就会被销毁了 这个让人比较郁闷 如何才能让这个activity不被销毁呢 背景分割线
  • 【VUE3】ElementUI--el-date-picker下拉控件样式修改(高亮显示设置)

    ElementUI el date picker下拉控件样式修改 一些废话 事发背景 实现效果 实现思路 总结和完整代码 参考资料 一些废话 默默做前端 分享一些自己在项目需求实现中遇到的奇妙问题 主要是网上搜索不到解决办法自己解决后的总结
  • cell基础概念

    1 spare cell 备用cell 共流片时进行function eco和metal eco使用 使用方法 add spare cells add spare cells cell name spare1 lib cell AND2 O
  • Unity 按键输入系统(一)

    这段时间制作了游戏内的操作系统 主要制作的原因是 在游戏内很多按键是公用的 但是不同位置的处理逻辑不同 比如在最外层界面上 可以使用ESC打开菜单 但是在二级界面里 使用ESC是返回上个界面 如果要使用判断制作的话 会产生很强的耦合性 要在