I recently needed to learn how to rebind controls for my game, and ALL of the resources I found online left unanswered questions, unfixed bugs, and were thrown together quickly for a "test" scene without much thought as to how it might work for an actual commercial game.
So for this tutorial I spent LOTS of time figuring out how to get it working the way I would want it for a commercial game.
This will show you everything from the ground up, from creating a new controls input action asset, to my preferred input manager, to setting up separate re-bindings for both keyboard AND gamepad.
Bug fix:
A bug was found where, if you separate a composite binding (ie. A vector2 up/down/left/right binding) into 4 separate bindings that you want to rebind, a duplication was possible within the composite binding itself.
To fix this, you'll need to change the CheckDuplicateBindings functions to the following:
private bool CheckDuplicateBindings(InputAction action, int bindingIndex, bool allCompositeParts = false)
{
InputBinding newBinding = action.bindings[bindingIndex];
int currentIndex = -1;
foreach (InputBinding binding in action.actionMap.bindings)
{
currentIndex++;
if (binding.action == newBinding.action)
{
if (binding.isPartOfComposite && currentIndex != bindingIndex)
{
if (binding.effectivePath == newBinding.effectivePath)
{
Debug.Log("Duplicate binding found in composite: " + newBinding.effectivePath);
return true;
}
}
else
{
continue;
}
}
if (binding.effectivePath == newBinding.effectivePath)
{
Debug.Log("Duplicate binding found: " + newBinding.effectivePath);
return true;
}
}
if (allCompositeParts)
{
for (int i = 1; i < bindingIndex; i++)
{
if (action.bindings[i].effectivePath == newBinding.overridePath)
{
//Debug.Log("Duplicate binding found: " + newBinding.effectivePath);
return true;
}
}
}
return false;
}
This also affects the "reset" button, so you'll need to change the ResetBinding function to the below as well:
private void ResetBinding(InputAction action, int bindingIndex)
{
InputBinding newBinding = action.bindings[bindingIndex];
string oldOverridePath = newBinding.overridePath;
action.RemoveBindingOverride(bindingIndex);
int currentIndex = -1;
foreach (InputAction otherAction in action.actionMap.actions)
{
currentIndex++;
InputBinding currentBinding = action.actionMap.bindings[currentIndex];
if (otherAction == action)
{
if (newBinding.isPartOfComposite)
{
if (currentBinding.overridePath == newBinding.path)
{
otherAction.ApplyBindingOverride(currentIndex, oldOverridePath);
}
}
else
{
continue;
}
}
for (int i = 0; i < otherAction.bindings.Count; i++)
{
InputBinding binding = otherAction.bindings[i];
if (binding.overridePath == newBinding.path)
{
otherAction.ApplyBindingOverride(i, oldOverridePath);
}
}
}
}