I am building a game, in which you control a character, which has different abilities. The abilities are activated by hotkeys (on a standard keyboard). To set this up im using unitys new inputsystem with a generacted c-class.
For the sake of clarity of the below code i have to mention, that my generated c-class is named PlayerInput.
Some variable names use spell instead of ability. Unfortunately i did not keep this 100% consistent.
Below is the code, which i use to setup the hotkeys. I have reduced my orginal code to the part relevant to this question.
public class PlayerCasting : MonoBehaviour {
private PlayerInput controls;
public PlayerAbility[] abilityList; // PlayerAbility is a class i have written. For the purpose of this Question it should be enough to know, that this array contains the useable abilities
private void Awake() {
controls = new PlayerInput();
}
private void OnEnable() {
controls.spellkeys.Enable(); // spellkeys is the name of the used ActionMap
}
private void OnDisable() {
controls.spellkeys.Disable();
}
void Start() {
SetUpSpellEvents();
}
void SetUpSpellEvents() {
InputActionMap spellKeys = ((InputActionMap) controls.spellkeys);
// int[] dummy = new int[spellKeys.actions.Count];
// for (int i = 0; i < dummy.Length; i++)
// dummy[i] = i;
// foreach (int i in dummy) {
// if (i >= abilityList.Length || abilityList[i] == null) continue;
// spellKeys.actions[i].started += _ => ActivateAbility(i);
// }
foreach (int i in Enumerable.Range(0, spellKeys.actions.Count+1)) {
if (i >= abilityList.Length || abilityList[i] == null) continue;
spellKeys.actions[i].started += _ => ActivateAbility(i);
}
// for (int i = 0; i < spellKeys.actions.Count; i++) {
// if (i >= abilityList.Length || abilityList[i] == null)
// continue;
// spellKeys.actions[i].started += _ => ActivateAbility(i);
// }
// int i = -1;
// foreach (InputAction inputAction in spellKeys) {
// i++;
// if (i >= abilityList.Length || abilityList[i] == null)
// continue;
// inputAction.started += _ => ActivateAbility(i);
// }
}
void ActivateAbility(int abilityPosition) {
PlayerAbility ability = abilityList[abilityPosition];
// Do something with ability
}
}
You may note, that the SetUpSpellEvents-function has 4 variants of the for- / foreach-loop setting up the event-listeners. 3 are comment out and 1 is currently used. All 4 variants should to the same thing (in my opinion).
The first 2 variants of the loop work, while the last 2 do not work.
By not working i mean, that all InputActions-started-events call the function ActivateAbility() with the same value for the int-Parameter abilityPosition (e.g. spellKeys.actions.Count / spellKeys.actions.Count-1). In both cases this should be the final value for i.
To be even more precise:
Pressing a key for a InputAction in the used ActionMap (which consists of 10 InputActions) results in:
with either of the first 2 variants:
Pressing the key for the first InputAction calls the function ActivateAbility(0)
Pressing the key for the second InputAction calls the function ActivateAbility(1)
…
Pressing the key for the last InputAction calls the function ActivateAbility(9)
if im using the third variant
Pressing the key for the first InputAction calls the function ActivateAbility(10)
…
Pressing the key for the last InputAction calls the function ActivateAbility(10)
if im using the fourth variant
Pressing the key for the first InputAction calls the function ActivateAbility(9)
…
Pressing the key for the last InputAction calls the function ActivateAbility(9)
My Question is: Why exactly do the last 2 loop-variants not work. Why is ActivateAbility() always called with the same (final?) value of i?