设计一个指令监听模块,监听并发布用户的输入指令或AI的指令,便于组合和拓展功能。

InputModule

在Scripts——Module文件夹内新建Input文件夹,新建InputModule

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
using System;
using System.Collections.Generic;
using UnityEngine;

public interface IInputModule
{
void AddKeyListener(KeyCode code);
void AddMouseListener(int code);
void RemoveKeyListener(KeyCode code);
void RemoveMouseListener(int code);
}

public class InputModule: IInputModule
{
//这里的Value指的是添加了当前KeyCode的监听的数量。同理下面Mouse也是
private readonly Dictionary<KeyCode, int> _keyCodeDic;
private readonly Dictionary<int, int> _mouseDic;
private Action<KeyCode,InputState> _keyEvent;
private Action<int,InputState> _mouseEvent;

public int ListenerCount
{
get
{
if (_keyCodeDic == null || _mouseDic == null) return 0;
return _keyCodeDic.Count + _mouseDic.Count;
}
}
public InputModule()
{
_keyCodeDic = new Dictionary<KeyCode, int>();
_mouseDic = new Dictionary<int, int>();
}
public void AddKeyListener(KeyCode code)
{
if (_keyCodeDic.ContainsKey(code))
{
_keyCodeDic[code]++;
}
else
{
_keyCodeDic.Add(code, 1);
}
}
public void AddMouseListener(int code)
{
if (_mouseDic.ContainsKey(code))
{
_mouseDic[code]++;
}
else
{
_mouseDic.Add(code, 1);
}
}

public void RemoveKeyListener(KeyCode code)
{
if (_keyCodeDic.ContainsKey(code))
{
_keyCodeDic[code]--;
if (_keyCodeDic[code] <= 0)
{
_keyCodeDic.Remove(code);
}
}
else
Debug.LogError("当前指令并没有被监听:" + code.ToString());
}
public void RemoveMouseListener(int code)
{
if (_mouseDic.ContainsKey(code))
{
_mouseDic[code]--;
if (_mouseDic[code] <= 0)
{
_mouseDic.Remove(code);
}
}
else
Debug.LogError("当前鼠标指令并没有被监听:" + code.ToString());
}
public void AddKeyEvent(Action<KeyCode, InputState> keyEvent)
{
_keyEvent = keyEvent;
}
public void AddMouseEvent(Action<int, InputState> mouseEvent)
{
_mouseEvent = mouseEvent;
}
public void Execute()
{
if (_keyEvent != null)
{
foreach (var item in _keyCodeDic)
{
if (Input.GetKeyDown(item.Key))
{
_keyEvent.Invoke(item.Key, InputState.DOWN);
}
if (Input.GetKey(item.Key))
{
_keyEvent.Invoke(item.Key, InputState.PRESS);
}
if (Input.GetKeyUp(item.Key))
{
_keyEvent.Invoke(item.Key, InputState.UP);
}

}
}
if (_mouseEvent != null)
{
foreach (var item in _mouseDic)
{
if (Input.GetMouseButtonDown(item.Key))
{
_mouseEvent.Invoke(item.Key, InputState.DOWN);
}
if (Input.GetMouseButton(item.Key))
{
_mouseEvent.Invoke(item.Key, InputState.PRESS);
}
if (Input.GetMouseButtonUp(item.Key))
{
_mouseEvent.Invoke(item.Key, InputState.UP);
}

}
}
}

}
public enum InputState
{
DOWN,
PRESS,
UP
}

ListenerCount属性表示当前是否有按键或鼠标在监听

这里的AddKeyListenerAddMouseListener仅仅是为了计数监听个数而已,并没有方法传进来。

AddKeyEventAddMouseEvent设置管理器发布事件的方法。

Execute每帧调用,用来判断哪些已经添加监听的按键按下了。

先通过AddKeyListenerAddMouseListener把需要监听的按键注册进来以进行计数,然后在AddKeyEventAddMouseEvent中添加发布事件方法,最后在Execute中将监听按键发布出去。

真正的按键监听方法是通过消息系统管理的,输入模块并不管。

InputMgr

在Logic文件夹下新建Manager文件夹,新建InputMgr

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
using UnityEngine;

public class InputMgr : NormalSingleton<InputMgr>, IInputModule, IUpdate
{
private readonly InputModule _inputModule;
private readonly bool _updating;
public InputMgr()
{
_updating = false;
_inputModule = new InputModule();
_inputModule.AddKeyEvent(KeyEvent);
_inputModule.AddMouseEvent(MouseEvent);
}

private void KeyEvent(KeyCode code, InputState state)
{
MessageMgr.Instance.DispatchMsg(GetKey(code,state), state);
}
private void MouseEvent(int code, InputState state)
{
//这里必须使用code.ToString,否则会和MsgEvent里面的消息ID搞混。
MessageMgr.Instance.DispatchMsg(GetKey(code,state), state);
}
public string GetKey(KeyCode code, InputState state)
{
return code.ToString() + state.ToString();
}
public string GetKey(int code, InputState state)
{
return code.ToString() + state.ToString();
}
public void AddKeyListener(KeyCode code)
{
_inputModule.AddKeyListener(code);
AddUpdate();
}

public void AddMouseListener(int code)
{
_inputModule.AddMouseListener(code);
AddUpdate();
}
private void AddUpdate()
{
if( !_updating )
{
LifeCycleMgr.Instance.Add(LifeName.UPDATE, this);
}
}

public void RemoveKeyListener(KeyCode code)
{
_inputModule.RemoveKeyListener(code);
RemoveUpdate();
}

public void RemoveMouseListener(int code)
{
_inputModule.RemoveMouseListener(code);
RemoveUpdate();
}
private void RemoveUpdate()
{
if (_inputModule.ListenerCount <= 0)
{
LifeCycleMgr.Instance.Remove(LifeName.UPDATE, this);
}
}

public void UpdateFun()
{
_inputModule.Execute();
}
}

实现GetKey方法,配合后面讲到的重构后的消息系统,让每个按键和状态都有一个单独的键值,优化监听效率。

通过InputMgr启用输入模块,并且通过消息系统分发。

实现IUpdate接口,将输入模块的Execute传入。