unity改键系统_传统版

本文主要面向 unity内置传统版本输入检测 系统 并非InputSystem

本文代码针对项目特殊定制,酌情依据情况修改

系统设计

改建系统设计

存储中介Asset

HotKeyMap用于每一个热键功能的实体数据类型。

HotKeyMgrAsset用作存储中介Asset,在运行时读取或写入这里的数据。

注意:HotKeyMgrAsset存储的List数据集合引用和Mgr中是一致的,所以修改Mgr中的数据Asset中的数据也会被修改。如果多次修改统一保存的情况,这里就需要对Asset中的数据进行深克隆;而不是直接引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[System.Serializable]
public class HotKeyMap
{
public HotKey key;

public bool hold = false;

public List<KeyCode> defaultKeyCodes = new List<KeyCode>();
public List<KeyCode> currentKeyCodes = new List<KeyCode>();

public void RestKeys()
{
currentKeyCodes.Clear();
currentKeyCodes.AddRange(defaultKeyCodes);
}

/// <summary>
/// 检查当前 热键是否与输入的热键相同
/// </summary>
/// <param name="hotKeyMap"></param>
/// <returns></returns>
public bool IsRepeat(List<KeyCode> hotKeyMap)
{
if (currentKeyCodes.Count > 0 && hotKeyMap.Count > 0 &&
currentKeyCodes.Count == hotKeyMap.Count)
{
for (var i = 0; i < currentKeyCodes.Count; i++)
{
if (currentKeyCodes[i] != hotKeyMap[i])
{
return false;
}
}

return true;
}

return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[CreateAssetMenu(fileName = "热键配置", menuName = "配置项目/热键配置", order = 0)]
public class HotKeyMgrAsset : ScriptableObject
{
public List<HotKeyMap> hotKeyMaps = new List<HotKeyMap>();

[ContextMenu("保存配置到本地")]
public void SaveData()
{
var json = JsonUtility.ToJson(this);
var path = Path.Combine(Application.persistentDataPath, "HotKeyMaps.json");
File.WriteAllText(path, json);
Debug.Log($"热键配置已保存:{path}");
}

[ContextMenu("从本地读取配置")]
public void LoadData()
{
var path = Path.Combine(Application.persistentDataPath, "HotKeyMaps.json");
if (File.Exists(path))
{
var json = File.ReadAllText(path);
JsonUtility.FromJsonOverwrite(json, this);
}
}

[ContextMenu("重置所有热键")]
private void RestAllKeyDefault()
{
hotKeyMaps.ForEach(x=>x.RestKeys());
}
}

热键配置示例

管理系统

使用HotKeySystem统一管理热键系统:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
namespace FFW.Template.HotKeyKit
{
/// <summary>
/// 热键系统 - 此系统基于传统输入系统
/// </summary>
public class HotKeySystem : ISystem
{
public Dictionary<HotKey, HotKeyMap> HotKeyMaps { get; private set; } = new Dictionary<HotKey, HotKeyMap>();

public HotKeyMgrAsset MgrAsset { get; private set; }

public void OpenSystem(params object[] args)
{
MgrAsset = Resources.Load<HotKeyMgrAsset>("热键配置");

HotKeyMaps.Clear();
MgrAsset.hotKeyMaps.ForEach(x =>
{
HotKeyMaps.Add(x.key, x);
});
}


#region 操作方法

/// <summary>
/// 检测快键输入
/// </summary>
/// <param name="key">功能key</param>
/// <returns></returns>
public bool CheckInput(HotKey key)
{
HotKeyMaps.TryGetValue(key, out HotKeyMap hotKeyMap);

if (hotKeyMap == null)
{
Debug.LogWarning($"HotKeyMap is null");
return false;
}

if (hotKeyMap.currentKeyCodes.Count == 0)
{
return false;
}

if (hotKeyMap.currentKeyCodes.Count == 1)
{
if (hotKeyMap.hold)
{
if (Input.GetKey(hotKeyMap.currentKeyCodes[0]))
{
return true;
}
}
else
{
if (Input.GetKeyDown(hotKeyMap.currentKeyCodes[0]))
{
return true;
}
}


return false;
}
else
{
if (Input.GetKey(hotKeyMap.currentKeyCodes[0]))
{
var allKeyPressed = true;

foreach (KeyCode keyCode in hotKeyMap.currentKeyCodes)
{
if (keyCode == hotKeyMap.currentKeyCodes[0])
{
continue;
}


if (!Input.GetKey(keyCode))
{
allKeyPressed = false;
break;
}
}

return allKeyPressed;
}
}

return false;
}

/// <summary>
/// 设置热键
/// </summary>
/// <param name="key"></param>
/// <param name="keyCodes"></param>
/// <param name="force"></param>
/// <returns></returns>
public bool SetHotKey(HotKey key, List<KeyCode> keyCodes, bool force = false)
{
if (HotKeyMaps.TryGetValue(key, out HotKeyMap hotKeyMap))
{
var res = CheckHotKeyRepeat(key, keyCodes);
if (res.Item2 != null && force)
{
res.Item2.RestKeys();
hotKeyMap.currentKeyCodes = keyCodes;
return true;
}
else if (res.Item1)
{
hotKeyMap.currentKeyCodes = keyCodes;
return true;
}
else if (res.Item2!=null)
{
Debug.LogWarning($"{hotKeyMap.key} 与热键重复:{res.Item2.key}");
return false;
}
}

return false;
}

/// <summary>
/// 检查热键是否重复
/// </summary>
/// <param name="key"></param>
/// <param name="keyCodes"></param>
/// <returns>(结果,重复map)</returns>
public (bool, HotKeyMap) CheckHotKeyRepeat(HotKey key, List<KeyCode> keyCodes)
{
if (HotKeyMaps.TryGetValue(key, out HotKeyMap hotKeyMap))
{
var list = HotKeyMaps.Values.ToList();
foreach (var cur in list)
{
if (key == cur.key)
{
continue;
}

if (cur.IsRepeat(keyCodes.ToList()))
{
return (true, cur);
}
}
}

return (false, null);
}


/// <summary>
/// 重置所有热键
/// </summary>
public void RestAllHotKeys()
{
foreach (var hotKeyMap in HotKeyMaps.Values)
{
hotKeyMap.RestKeys();
}
}

#endregion
}
}

按键监听

在游戏中通常是这样的:

监听检测

值得注意的是对于组合按键的监听,应该使用GetkeyUp,同时在监听时应该避免监听到鼠标的输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;

public class KeyBinder : MonoBehaviour, IPointerDownHandler
{
private HashSet<KeyCode> keysDown = new HashSet<KeyCode>();
private bool isRecording = false;
public TextMeshProUGUI displayText; // 用于显示当前按下的组合键

void Update()
{
if (isRecording)
{
foreach (KeyCode k in System.Enum.GetValues(typeof(KeyCode)))
{
if (Input.GetKeyUp(k) && k != KeyCode.Mouse0)
{
keysDown.Add(k);
// 更新显示的组合键
displayText.text = string.Join(" + ", keysDown);
isRecording = false;
SaveKeyCombination();
break;
}
else if (Input.GetKey(k) && k != KeyCode.Mouse0)
{
keysDown.Add(k);
displayText.text = string.Join(" + ", keysDown);
}
}
}
}

public void OnPointerDown(PointerEventData eventData)
{
// 如果不在记录,点击按钮开始记录组合键
isRecording = true;
displayText.text = "按下组合键...";
keysDown.Clear();
}

private void SaveKeyCombination()
{
// 这里只是简单地打印出组合键,实际应用中你可以保存到PlayerPrefs或者其他地方
string keyCombination = string.Join(", ", keysDown);
Debug.Log("保存的组合键: " + keyCombination);
}
}