Search Unity

Question Confused about event supcription of functions with int parameters

Discussion in 'Input System' started by pi_314159265, Dec 3, 2023.

  1. pi_314159265

    pi_314159265

    Joined:
    Aug 14, 2022
    Posts:
    29
    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.

    Code (CSharp):
    1. public class PlayerCasting : MonoBehaviour {
    2.     private PlayerInput controls;
    3.     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
    4.  
    5.     private void Awake() {
    6.         controls = new PlayerInput();
    7.     }
    8.  
    9.     private void OnEnable() {
    10.         controls.spellkeys.Enable(); // spellkeys is the name of the used ActionMap
    11.     }
    12.  
    13.     private void OnDisable() {
    14.         controls.spellkeys.Disable();
    15.     }
    16.  
    17.     void Start() {
    18.         SetUpSpellEvents();
    19.     }
    20.  
    21.     void SetUpSpellEvents() {
    22.         InputActionMap spellKeys = ((InputActionMap) controls.spellkeys);
    23.  
    24.         // int[] dummy = new int[spellKeys.actions.Count];
    25.         // for (int i = 0; i < dummy.Length; i++)
    26.         //     dummy[i] = i;
    27.         // foreach (int i in dummy) {
    28.         //     if (i >= abilityList.Length || abilityList[i] == null) continue;
    29.         //     spellKeys.actions[i].started += _ => ActivateAbility(i);
    30.         // }
    31.  
    32.         foreach (int i in Enumerable.Range(0, spellKeys.actions.Count+1)) {
    33.             if (i >= abilityList.Length || abilityList[i] == null) continue;
    34.             spellKeys.actions[i].started += _ => ActivateAbility(i);
    35.         }
    36.  
    37.         // for (int i = 0; i < spellKeys.actions.Count; i++) {
    38.         //     if (i >= abilityList.Length || abilityList[i] == null)
    39.         //         continue;
    40.         //     spellKeys.actions[i].started += _ => ActivateAbility(i);
    41.         // }
    42.  
    43.         // int i = -1;
    44.         // foreach (InputAction inputAction in spellKeys) {
    45.         //     i++;
    46.         //     if (i >= abilityList.Length || abilityList[i] == null)
    47.         //         continue;
    48.         //     inputAction.started += _ => ActivateAbility(i);
    49.         // }
    50.     }
    51.  
    52.     void ActivateAbility(int abilityPosition) {
    53.         PlayerAbility ability = abilityList[abilityPosition];
    54.         // Do something with ability
    55.     }
    56.  
    57. }
    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?
     
    Last edited: Dec 5, 2023
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,800