【Unity_Input System】Input System新输入系统(三)——在游戏中更换按键绑定
八、在游戏中更换按键绑定
1.Binding和CompositeBinding
- Binding只由一个部分组成,一般绑定单个按键或者摇杆
- CompositeBinding由两个以上部分组成,一般是用于将多个按键组成虚拟轴
更换按键绑定时,Binding和Composite Binding需要分别处理,对Composite Binding需要循环各个部分进行修改。
可以用InputBinding.isComposite来判断是否是Composite Binding
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CompositeBindingCheck : MonoBehaviour
{
MyAction inputActions;
private void Start()
{
inputActions = new MyAction();
Debug.Log("WASD:" + inputActions.Player.Test1.bindings[0].isComposite);
Debug.Log("Left Stick:" + inputActions.Player.Test1.bindings[1].isComposite);
}
}
控制台输出结果:
2.在UI中显示原本的按键绑定
1>显示Action名称
用到的API:InputAction.name
2>显示Binding名称
用到的API:InputAction.GetBindingDisplayString
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class RebindButtonTest : MonoBehaviour
{
//Action名
public Text actionLabel;
//Binding名
public Text bindingLabel;
[SerializeField]
public InputActionReference actionReference;
private void Start()
{
actionLabel.text = actionReference.name;
bindingLabel.text = actionReference.action.GetBindingDisplayString(0, out string deviceLayoutName, out string controlPath);
}
}
运行效果:
PS.InputActionReferrence是InputSystem的一个API,用来引用在InputActionAsset中已经设置过的InputAction,即使被引用的InputAction重命名,引用也不会丢失,
请查阅:Class InputActionReference | Input System | 1.3.0 (unity3d.com)
3.更换按键绑定
用到的API:InputAction.PerformInteractiveRebinding
请查阅:Class InputActionRebindingExtensions | Input System | 1.3.0 (unity3d.com)
How do I…? | Input System | 1.3.0 (unity3d.com)
注意Binding和Composite Binding需要分别处理,因为Composite Binding需要循环更换每个部分的按键绑定
下面的例子只是简单去测试怎么使用这个API去修改按键绑定,如果是实际项目需要,可以参考官方案例:Rebinding UI
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class RebindButtonTest : MonoBehaviour
{
//Action名
public Text actionLabel;
//Binding名
public Text bindingLabel;
//Binding的id
public string bindingId;
private int index;
[SerializeField]
public InputActionReference actionReference;
private InputActionRebindingExtensions.RebindingOperation RebindOperation;
private void Start()
{
//UI显示Action名
actionLabel.text = actionReference.name;
//获取BingdingID
/* 这里只是为了简单,所以手动选择要修改的binding,并且获取它的id
* 这个例子里面,第0层是WASD
* 第1层是composite的第1个部分W
* 第2层是composite的第2个部分S
* 第3层是composite的第3个部分A
* 第4层是composite的第4个部分D
* 第5层是左摇杆
*/
index = 0;
bindingId = actionReference.action.bindings[index].id.ToString();
//UI刷新Binding名
UpdateLabel(index);
}
/// <summary>
/// 开始替换
/// </summary>
/// <param name="index"></param>
public void StartInteractiveRebind()
{
//获取bindingIndex,Bingdings数组的下标,从0开始,如果action为空返回false
if (!CheckActionAndBinding(out int bindingIndex))
return;
// If the binding is a composite, we need to rebind each part in turn.
if (actionReference.action.bindings[bindingIndex].isComposite)
{
var firstPartIndex = bindingIndex + 1;
if (firstPartIndex < actionReference.action.bindings.Count && actionReference.action.bindings[firstPartIndex].isPartOfComposite)
PerformInteractiveRebind(actionReference, firstPartIndex, allCompositeParts: true);
}
else
{
PerformInteractiveRebind(actionReference, bindingIndex);
}
}
/// <summary>
/// 获取bindingIndex,Bingdings数组的下标,从0开始,如果action为空返回false
/// </summary>
/// <param name="index"></param>
private bool CheckActionAndBinding(out int bindingIndex)
{
bindingIndex = -1;
if (actionReference == null)
return false;
bindingIndex = actionReference.action.bindings.IndexOf(x => x.id == new System.Guid(bindingId));
return true;
}
private void PerformInteractiveRebind(InputAction action, int bindingIndex, bool allCompositeParts = false)
{
RebindOperation?.Cancel(); // Will null out m_RebindOperation.
void CleanUp()
{
RebindOperation?.Dispose();
RebindOperation = null;
}
// Configure the rebind.
RebindOperation = action.PerformInteractiveRebinding(bindingIndex)
.WithControlsExcluding("Mouse")//剔除鼠标
.OnCancel(
operation =>
{
CleanUp();
})
.OnComplete(
operation =>
{
UpdateLabel(index);
CleanUp();
// If there's more composite parts we should bind, initiate a rebind
// for the next part.
if (allCompositeParts)
{
var nextBindingIndex = bindingIndex + 1;
if (nextBindingIndex < action.bindings.Count && action.bindings[nextBindingIndex].isPartOfComposite)
PerformInteractiveRebind(action, nextBindingIndex, true);
}
});
RebindOperation.Start();
}
/// <summary>
/// UI刷新binding名
/// </summary>
/// <param name="index"></param>
private void UpdateLabel(int index)
{
bindingLabel.text = actionReference.action.GetBindingDisplayString(index, out string deviceLayoutName, out string controlPath);
}
}
运行效果:
4.按键的保存
//Load:
var rebinds = PlayerPrefs.GetString("rebinds");
if (!string.IsNullOrEmpty(rebinds))
actions.LoadBindingOverridesFromJson(rebinds);
//Save:
var rebinds = actions.SaveBindingOverridesAsJson();
PlayerPrefs.SetString("rebinds", rebinds);
5.按键恢复默认设置
用到的API:InputAction.RemoveBindingOverride
请查阅:Class InputActionRebindingExtensions | Input System | 1.3.0 (unity3d.com)
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class RebindButtonTest : MonoBehaviour
{
//Action名
public Text actionLabel;
//Binding名
public Text bindingLabel;
//Binding的id
public string bindingId;
private int index;
[SerializeField]
public InputActionReference actionReference;
private InputActionRebindingExtensions.RebindingOperation RebindOperation;
private void Start()
{
//UI显示Action名
actionLabel.text = actionReference.name;
//获取BingdingID
/* 这里只是为了简单,所以手动选择要修改的binding,并且获取它的id
* 这个例子里面,第0层是WASD
* 第1层是composite的第1个部分W
* 第2层是composite的第2个部分S
* 第3层是composite的第3个部分A
* 第4层是composite的第4个部分D
* 第5层是左摇杆
*/
index = 0;
bindingId = actionReference.action.bindings[index].id.ToString();
//UI刷新Binding名
UpdateLabel(index);
}
//开始替换
public void StartInteractiveRebind()
{
//获取bindingIndex,Bingdings数组的下标,从0开始,如果action为空返回false
if (!CheckActionAndBinding(out int bindingIndex))
return;
// If the binding is a composite, we need to rebind each part in turn.
if (actionReference.action.bindings[bindingIndex].isComposite)
{
var firstPartIndex = bindingIndex + 1;
if (firstPartIndex < actionReference.action.bindings.Count && actionReference.action.bindings[firstPartIndex].isPartOfComposite)
PerformInteractiveRebind(actionReference, firstPartIndex, allCompositeParts: true);
}
else
{
PerformInteractiveRebind(actionReference, bindingIndex);
}
}
//获取bindingIndex,Bingdings数组的下标,从0开始,如果action为空返回false
private bool CheckActionAndBinding(out int bindingIndex)
{
bindingIndex = -1;
if (actionReference == null)
return false;
bindingIndex = actionReference.action.bindings.IndexOf(x => x.id == new System.Guid(bindingId));
return true;
}
private void PerformInteractiveRebind(InputAction action, int bindingIndex, bool allCompositeParts = false)
{
RebindOperation?.Cancel(); // Will null out m_RebindOperation.
void CleanUp()
{
RebindOperation?.Dispose();
RebindOperation = null;
}
// Configure the rebind.
RebindOperation = action.PerformInteractiveRebinding(bindingIndex)
.WithControlsExcluding("Mouse")//剔除鼠标
.OnCancel(
operation =>
{
CleanUp();
})
.OnComplete(
operation =>
{
UpdateLabel(index);
CleanUp();
// If there's more composite parts we should bind, initiate a rebind
// for the next part.
if (allCompositeParts)
{
var nextBindingIndex = bindingIndex + 1;
if (nextBindingIndex < action.bindings.Count && action.bindings[nextBindingIndex].isPartOfComposite)
PerformInteractiveRebind(action, nextBindingIndex, true);
}
});
RebindOperation.Start();
}
/// <summary>
/// UI刷新binding名
/// </summary>
/// <param name="index"></param>
private void UpdateLabel(int index)
{
bindingLabel.text = actionReference.action.GetBindingDisplayString(index, out string deviceLayoutName, out string controlPath);
}
public void ResetToDefault()
{
if (!CheckActionAndBinding(out var bindingIndex))
return;
if (actionReference.action.bindings[bindingIndex].isComposite)
{
// It's a composite. Remove overrides from part bindings.
for (var i = bindingIndex + 1; i < actionReference.action.bindings.Count && actionReference.action.bindings[i].isPartOfComposite; ++i)
actionReference.action.RemoveBindingOverride(i);
}
else
{
actionReference.action.RemoveBindingOverride(bindingIndex);
}
UpdateLabel(index);
}
}
运行效果: