- Home /
Why is my function/coroutine executing a second time?
I've taken up the task of writing my own Input Manager since the default Unity one doesn't allow ingame rebinding nor retrieval of bound keys. During this process I've come across an issue where triggering a key to be rebound works, but if I press a second key afterwards, it will then try to bind that key.
First off, I have declared two classes to make my life easier here:
[System.Serializable]
public class Control {
public string controlName;
public string[] buttons;
public Control() {
buttons = new string[2];
}
}
[System.Serializable]
public class Rebinder {
public int index; // Index of control being rebound. -1 means none
public bool b1; // Is it button 1 being rebound? false = button 2
public string key; // New key to bind
public ControlRebinder sender;
public Rebinder() {
index = -1;
b1 = false;
}
}
The Control class is fairly self-explanatory, it acts a lot like an axis in the default Input Manager, with up to 2 buttons bound to one control.
The Rebinder class is only being used once, and is used to store all the necessary rebinding information together. If there's a better way to do this I'd be glad to use it.
I've then created two string arrays, one for containing unity-recognised button on the keyboard (keyList), and one auto-populated at start for controllers (padList). I also have an array of Controls, called controlList.
The Update loop checks if there is a key that needs to be rebound, and if there is it uses a coroutine to get the next input:
void Update () {
if(rebinding.index > -1) {
if(rebinding.key == null || rebinding.key == "") {
StartCoroutine(getNextKey(output => rebinding.key = output));
}
if(rebinding.key != null && rebinding.key != "") {
if(rebinding.b1) {
controlList[rebinding.index].buttons[0] = rebinding.key;
}
else {
controlList[rebinding.index].buttons[1] = rebinding.key;
}
rebinding.index = -1;
rebinding.key = null;
rebinding.sender.controlRebound(rebinding.key);
rebinding.sender = null;
}
}
}
The getNextKey function is here:
IEnumerator getNextKey(System.Action<string> key) {
yield return new WaitForSeconds(0.2f);
// Check for controller input
for(int v = 0; v <= 19; v++) {
if(Input.GetKey("joystick button "+v)) {
for(int x = 1; x <= 4; x++) {
if(Input.GetKey("joystick "+x+" button "+v)) {
key("joystick "+x+" button "+v);
yield break;
}
}
}
}
// Wait until a key is pressed
while (!Input.anyKey){
yield return null;
}
// Go through each valid key and see if it was pressed
foreach(string k in keyList) {
if(Input.GetKey(k)) {
key(k);
yield break;
}
}
// If not, unbind the key
key ("none");
}
and the function that flags a control for rebinding is here:
public bool rebindControl(ControlRebinder sender, int controlIndex, int buttonIndex) {
// Flags a control to be rebound, as long as no other control is being rebound
if(rebinding.index > -1) {
return false;
}
// Pass control details to rebinding variable
rebinding.index = controlIndex;
rebinding.b1 = (buttonIndex == 0)?true:false;
rebinding.sender = sender;
return true;
}
So basically, when I call rebindControl() it will correctly open the right control to be bound, and when I press a button it will correctly accept that input and bind it to the control. However, if I press another button at any time after, without activating another control to be bound, it will load rebinding.key with the key I press. The result of this is that when I next bind a control, it will be bound to the already-loaded key before I press anything.
I am watching the variables in the editor when I do this, and rebinding.index is definitely being set to -1 at the right time, and rebinding.key is definitely being cleared. It will also only occur a second time, not a third.