許多單機游戲都帶有游戲內按鍵修改功能,今天就來實現一個。其本質上還是對KeyCode 進一步封裝。
配置簡單方便如下圖:
我將按鍵分為3種:
1、按下或持續按下會觸發。
2、帶有值的輸入,當按下時會持續增加,松開時會不斷減少,值會有一個范圍,超出范圍將會是邊界那個值。
3、類似Horizontal ,Verticale的兩個按鍵控制一個值。
代碼如下:
[Serializable] public class Key { public string name; public KeyCode keyCode; public KeyCodeType keyType = KeyCodeType.Once; [HideInInspector] public bool IsDown = false; [HideInInspector] public bool enable = true; } public enum KeyCodeType { Once, Continuity } [Serializable] public class ValueKey { public string name; public Vector2 range=new Vector2(0,1); public float currValue=0; public float addSpeed = 3f; public KeyCode keyCode; [HideInInspector] public bool enable = true; } [Serializable] public class AxisKey { public string name; public float value=0; public float addSpeed=5; public Vector2 range=new Vector2(-1,1); public KeyCode min, max; [HideInInspector] public bool enable = true; public void SetKey(KeyCode a,KeyCode b) { min = a; max = b; } }
將按鍵數據制作成ScriptObject 方便配置
代碼如下:
[CreateAssetMenu] public class InputData : ScriptableObject { public List<Key> keys=new List<Key>() { new Key() }; public List<ValueKey> valueKeys=new List<ValueKey>() { new ValueKey()}; public List<AxisKey> axisKeys=new List<AxisKey>() {new AxisKey()}; public void SetKey(string name,KeyCode key) { Key key1= GetKey(name); if (key1!=null) { key1.keyCode = key; } } public void SetAxisKey(string name,KeyCode a,KeyCode b) { AxisKey axisKey = GetAxisKey(name); if (axisKey != null) { axisKey.SetKey(a,b); } } public void SetValueKey(string name,KeyCode key) { ValueKey valueKey = GetValueKey(name); if (valueKey!=null) { valueKey.keyCode = key; } } public ValueKey GetValueKey(string name) { int len = valueKeys.Count; for (int i = 0; i < len; i++) { if (valueKeys[i].name==name) { return valueKeys[i]; } } Debug.LogError("ValueKey:" + name + "不存在"); return null; } public AxisKey GetAxisKey(string name) { int len = axisKeys.Count; for (int i = 0; i < len; i++) { if (axisKeys[i].name == name) { return axisKeys[i]; } } Debug.LogError("AxisKey:" + name + "不存在"); return null; } public Key GetKey(string name) { int len = keys.Count; for (int i = 0; i < len; i++) { if (keys[i].name==name) { return keys[i]; } } Debug.LogError("Key:"+name+"不存在"); return null; } public float Axis(string name) { AxisKey axisKey = GetAxisKey(name); if (axisKey != null) { return axisKey.value; } return 0; } public bool GetKeyDown(string name) { Key key = GetKey(name); if (key != null) { return key.IsDown; } return false; } public float GetValue(string name) { ValueKey valueKey = GetValueKey(name); if (valueKey != null) { return valueKey.currValue; } return 0; } public void SetKeyEnable(string name,bool enable) { Key key = GetKey(name); if (key!=null) { key.enable = enable; key.IsDown = false; } } public void SetValueKeyEnable(string name,bool enable) { ValueKey valueKey = GetValueKey(name); if (valueKey!=null) { valueKey.enable = enable; valueKey.currValue = 0; } } public void SetAxisKeyEnable(string name,bool enable) { AxisKey axisKey = GetAxisKey(name); if (axisKey!=null) { axisKey.enable = enable; axisKey.value = 0; } } /// <summary> /// 每幀更新 /// </summary> public void AcceptInput() { UpdateKeys(); UpdateValueKey(); UpdateAllAxisKey(); } private void UpdateKeys() { for (int i = 0; i < keys.Count; i++) { if (keys[i].enable) { keys[i].IsDown = false; switch (keys[i].keyType) { case KeyCodeType.Once: if (Input.GetKeyDown(keys[i].keyCode)) { keys[i].IsDown = true; } break; case KeyCodeType.Continuity: if (Input.GetKey(keys[i].keyCode)) { keys[i].IsDown = true; } break; } } } } private void UpdateValueKey() { int len = valueKeys.Count; for (int i = 0; i < len; i++) { if (valueKeys[i].enable) { if (Input.GetKey(valueKeys[i].keyCode)) { valueKeys[i].currValue = Mathf.Clamp(valueKeys[i].currValue + valueKeys[i].addSpeed * Time.deltaTime, valueKeys[i].range.x, valueKeys[i].range.y); } else { valueKeys[i].currValue = Mathf.Clamp(valueKeys[i].currValue - valueKeys[i].addSpeed * Time.deltaTime, valueKeys[i].range.x, valueKeys[i].range.y); } } } } private void UpdateAllAxisKey() { int len = axisKeys.Count; for (int i = 0; i < len; i++) { UpdateAxisKey(axisKeys[i]); } } private void UpdateAxisKey(AxisKey axisKey) { if (!axisKey.enable) return; if (Input.GetKey(axisKey.min) || Input.GetKey(axisKey.max)) { if (Input.GetKey(axisKey.min)) axisKey.value = Mathf.Clamp(axisKey.value - axisKey.addSpeed * Time.deltaTime, axisKey.range.x, axisKey.range.y); if (Input.GetKey(axisKey.max)) axisKey.value = Mathf.Clamp(axisKey.value + axisKey.addSpeed * Time.deltaTime, axisKey.range.x, axisKey.range.y); } else if (Input.GetKey(axisKey.min) && Input.GetKey(axisKey.max)) { axisKey.value = 0; } else { axisKey.value = Mathf.Lerp(axisKey.value, 0, Time.deltaTime * axisKey.addSpeed); } } }
參考Input調用方式,配置類似的調用方式使用起來和原來幾乎沒什么改變
public class InputManager : MonoBehaviour { public string path= "New Input Data"; static InputData inputData; static bool activeSetKey = false; static Action<KeyCode> setKey; private void Awake() { inputData = Resources.Load<InputData>(path); if (inputData == null) { throw new Exception("inputData:無法加載"); } } public void OnGUI() { if (!activeSetKey) return; Event e = Event.current; if (e.isKey&&setKey!=null) { KeyCode key = e.keyCode; Debug.Log(key); setKey(key); setKey = null; activeSetKey = false; } } private void Update() { inputData.AcceptInput(); } public static void StartSetKey(Action<KeyCode> key) { setKey = key; activeSetKey = true; } public static float GetAxis(string name) { return inputData.Axis(name); } public static bool GetKeyDown(string name) { return inputData.GetKeyDown(name); } public static float GetValueKey(string name) { return inputData.GetValue(name); } public static void SetKey(string name,KeyCode key) { inputData.SetKey(name,key); } public static void SetValueKey(string name,KeyCode key) { inputData.SetValueKey(name,key); } public static void SetAxisKey(string name,KeyCode a,KeyCode b) { inputData.SetAxisKey(name,a,b); } }
使用時候需要修改InputManager的執行順序,保證輸入在其它腳本調用的前方
使用案例包含三種按鍵和修改按鍵:
代碼如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class TestInput : MonoBehaviour { void Update() { if (InputManager.GetKeyDown("Jump")) { Debug.Log("Jump"); } if (InputManager.GetKeyDown("Attack")) { Debug.Log("Attack"); } if (Mathf.Abs(InputManager.GetAxis("Horizontal"))>0.1f) { Debug.Log("Horizontal:" + InputManager.GetAxis("Horizontal")); } if (Mathf.Abs(InputManager.GetAxis("Vertical")) > 0.1f) { Debug.Log("Vertical:" + InputManager.GetAxis("Vertical")); } if (InputManager.GetValueKey("Space")>0.1f) { Debug.Log("Space:"+InputManager.GetValueKey("Space")); } if (Input.GetMouseButtonDown(0)) { InputManager.StartSetKey((keycode)=> { InputManager.SetKey("Jump", keycode); }); } } }