Search Unity

user-customizable controls

Discussion in 'Input System' started by yoyobbi, Apr 13, 2016.

  1. yoyobbi

    yoyobbi

    Joined:
    Nov 26, 2013
    Posts:
    16
    Many games allow players to customize the input controls, mapping in-game actions to new keys and buttons to suit personal preference or new devices. When we launched Homeworld: Deserts of Kharak we got quite a bit of criticism for not allowing players to rebind hot keys (a pretty standard feature for RTS games). We did add the feature post-launch, but it was non-trivial to implement.

    Does the new input system provide a way for end users to customize the controls? I've briefly reviewed the architecture documentation and I don't see customization called out explicitly but I may have overlooked something.

    If customization isn't built into the system, how would a developer go about enabling control customization for their game?

    (By the way, thanks for the in-depth preview of the new input system and opportunity to provide feedback, this is great.)
     
  2. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Yup, customization is the very first requirement that made it on the list of the new system given that it was the most glaring shortcoming of the current one.

    The demo includes a rudimentary UI that allows you to rebind controls. You'll also see help texts in the demo change based on the bindings you've customized. Persistence of the bindings is kinda implemented but not fully hooked up (and there's a problem in there in how we deal with modified state; but that's something specific to the prototype).
     
    yoyobbi likes this.
  3. rabirland

    rabirland

    Joined:
    Nov 22, 2014
    Posts:
    29
    You can already... I worked for about 3 hours to make it works, but it does...
    Here is how to do it:
    Make a script...
    First you need the PlayerInput of course
    and you need its control schemes in the action map:

    Code (CSharp):
    1. PlayerInput playerInput;
    2. List<ControlScheme> controlScheme;
    after that you need the initialization put it in the Start or whatever you need:
    Code (CSharp):
    1. controlScheme = playerInput.GetAction<XXX>.actionMap.controlSchemes;
    Take care that you need the actionMap's controlSchemes List because the playerInput.GetAction<XXX>.controlScheme does not retrieve multiply input source like Gamepad and Keyboard...
    in the actionMap.controlSchemes list you can access all of them...

    Now, you need two method in your input manager that waits for a key and the other that retrieves the very first pressed key / moved axis, etc... here is mine:

    Code (CSharp):
    1. static void WaitForAny (InputControlDescriptor descriptor)
    2.     {
    3.         if (!waitingForKey) {
    4.             inputControlDescriptor = descriptor;
    5.             waitingForKey = true;
    6.             InputSystem.ListenForBinding (BindInputControl);
    7.         }
    8.     }
    9.  
    10.     static bool BindInputControl(InputControl control)
    11.     {
    12.         actionMapInput.BindControl(inputControlDescriptor, control, false);
    13.         inputControlDescriptor = null;
    14.         if (onGotInput != null) onGotInput(0);
    15.         Debug.Log(control.name);
    16.         waitingForKey = false;
    17.         return true;
    18.     }
    However this is just my raw waiting code... I made 2 wrapper both for Button Input and Axis Input:
    Code (CSharp):
    1. public static void WaitForAxis (BlackenedInputBindings axisBind, BlackenedInputSources inputSource, bool positive)
    2.     {
    3.         if (controlScheme != null)
    4.             WaitForAny(positive ? controlScheme[(int)inputSource].bindings[(int)axisBind].buttonAxisSources[0].positive : controlScheme[(int)inputSource].bindings[(int)axisBind].buttonAxisSources[0].negative);
    5.     }
    6.  
    7.     public static void WaitForKey (BlackenedInputBindings buttonBind, BlackenedInputSources inputSource)
    8.     {
    9.         Debug.Log(controlScheme[(int)inputSource].bindings[2].sources[0]);
    10.         if (controlScheme != null)
    11.             WaitForAny(controlScheme[(int)inputSource].bindings[(int)buttonBind].sources[0]);
    12.     }
    And thats all... With a simple C# event handler in your InputManager, you can easily bind a specific button to retrieve the input code you got in the BindInputControl method... Mine is for example the if (onGotInput != null) onGotInput(0);

    and in my Button's code:

    Code (CSharp):
    1. public void OnClick()
    2.     {
    3.         if (!CustomInputManager.waitingForKey)
    4.         {
    5.             displayText.text = LanguageManager.GetText("Lang_WaitForKey");
    6.             CustomInputManager.onGotInput += X;
    7.             if (isAxis)
    8.                 CustomInputManager.WaitForAxis(bindIndex, inputSource, positive);
    9.             else
    10.                 CustomInputManager.WaitForKey(bindIndex, inputSource);
    11.         }
    12.     }
    And the method binded to the event, which get called when the User makes an input:

    Code (CSharp):
    1. void OnAnyKeyPress(int keyCode)
    2.     {
    3.         CustomInputManager.onGotInput -= X;
    4.         displayText.text = LanguageManager.GetText("Got it!!!");
    5.     }
    Note: This binds a new key to the actionMap ONLY while your game is running... However you can easily save this code, and when your game starts, re-bind the codes again...
    I hope this helped :)
     
    dval and yoyobbi like this.
  4. yoyobbi

    yoyobbi

    Joined:
    Nov 26, 2013
    Posts:
    16
    Thanks for the all the details. I'm glad to hear customization was considered from the beginning. I will review and digest the approach and think about how we would apply it to RTS games.
     
  5. piyush1rajnish

    piyush1rajnish

    Joined:
    Jun 16, 2020
    Posts:
    1
    Can we do this by visual scripting