设计一个指令监听模块,监听并发布用户的输入指令或AI的指令,便于组合和拓展功能。
在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 { 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
属性表示当前是否有按键或鼠标在监听
这里的AddKeyListener
和AddMouseListener
仅仅是为了计数监听个数而已,并没有方法传进来。
AddKeyEvent
和AddMouseEvent
设置管理器发布事件的方法。
Execute
每帧调用,用来判断哪些已经添加监听的按键按下了。
先通过AddKeyListener
和AddMouseListener
把需要监听的按键注册进来以进行计数,然后在AddKeyEvent
和AddMouseEvent
中添加发布事件方法,最后在Execute
中将监听按键发布出去。
真正的按键监听方法是通过消息系统管理的,输入模块并不管。
在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) { 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
传入。