unity游戏内动态修改按键
许多单机游戏都带有游戏内按键修改功能,今天就来实现一个。其本质上还是对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); }); } } }