Search Unity

GetButton vs GetKey

Discussion in 'Scripting' started by GamesWerfer, Aug 16, 2019.

  1. GamesWerfer

    GamesWerfer

    Joined:
    Aug 3, 2019
    Posts:
    10
    I was told in the unity.learn basic scripting video that it is recommended to use GetButton for player input and I could specify my own controls. However, I found out I couldn't create new buttons in the Input section of the project settings and I am confused to how to create a simple w-a-s-d movement system using GetButton. So I went back to using GetKey which is the only function that I understand and I am able to use. Is it ok to create a system using GetKey functions only or should I use Getbutton instead? and how do I correctly use the GetButton function?
     
  2. gononono64

    gononono64

    Joined:
    Mar 1, 2015
    Posts:
    13
    Buttons are defined in the Input Manager <-under <-project settings<-(edit). In here you can modify or create (by adding to the size field) and customize each button to your liking. The name field will be what GetButton uses to check if the keys/axis defined in the input manager, are receiving input.

    https://docs.unity3d.com/Manual/class-InputManager.html
    https://docs.unity3d.com/ScriptReference/Input.GetButton.html

    ** ADDED NOTE**
    GetButton is really useful if you are trying to detect multiple keys for the same function. For instance, say you wanted to support keyboard input AND controller input. You would have to detect many input.getkeydown or w/e instead of just getting unity to do it for you by setting it in the above
     
    Last edited: Aug 20, 2019
  3. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,147
    Yes, it's completely fine to use GetKey. I've never used the GetButton function and will most likely never use it as this entire API is in the process of being replaced by a new one that functions completely differently.
     
  4. GamesWerfer

    GamesWerfer

    Joined:
    Aug 3, 2019
    Posts:
    10
    As far as I know GetKey is used to detect specific key inputs. But what if we want to change our forward button from 'w' into another key without changing the code? In my last few movement scripts, I declared public string variables which I use to specify movement keys so that I could edit them in the inspector. However, I'm still unsure whether this technique is reliable or not.
     
  5. GamesWerfer

    GamesWerfer

    Joined:
    Aug 3, 2019
    Posts:
    10
  6. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,147
    You can have remappable keys with GetKey. You just have to approach the problem correctly. For complete details on my solution check the blog entry below (it's not my blog but it's written by a fellow developer that I was discussing the problem with).

    http://luminaryapps.com/blog/configurable-input/

    To summarize you basically assign every single keyboard, mouse, and controller axis and button combo that is capable of existing in the Input Manager. You can do this manually but my recommendation is to use an editor script like the one described at the following blog entry as there are a few hundred entries to make.

    http://plyoung.appspot.com/blog/manipulating-input-manager-in-script.html

    After that you create a remapping system that sits on top of the Input Manager. There isn't a whole lot to it. It basically just stores a record of what each input is for each action the game has and when you remap an action it replaces the record with the new input data.

    If you don't want to build any of this yourself there is an asset (not mine) on the store that does all of what I described above for you, but I don't recommend wasting time with it. There is a new Input API coming out sometime by end of the year and it will replace everything as well as fully support remapping (last I checked it was two lines of code to do it).

    https://assetstore.unity.com/packages/tools/input-management/incontrol-14695
     
    Last edited: Aug 18, 2019
  7. Vryken

    Vryken

    Joined:
    Jan 23, 2018
    Posts:
    2,106
    You can create your own input system to handle this.
    This is the (trimmed-down) system I use for my game:
    Code (CSharp):
    1. [Serializable]
    2. public class InputAction {
    3.     [SerializeField] private KeyCode button;
    4.     [SerializeField] private ScrollInput scroll;
    5.  
    6.     public bool Started => Input.GetKeyDown(Button) || InputScrollFirstFrame();
    7.     public bool Held => Input.GetKey(Button) || InputScroll();
    8.     public bool Released => Input.GetKeyUp(Button) && !InputScroll();
    9.  
    10.     private bool FirstFrameScroll { get; set; } = true;
    11.  
    12.     private bool InputScroll() {
    13.         bool scrollDetected = false;
    14.         float mouseDeltaY = Input.mouseScrollDelta.y;
    15.  
    16.         if(Scroll == ScrollInput.Both && mouseDeltaY != 0) {
    17.             scrollDetected = true;
    18.         }
    19.         else if(Scroll == ScrollInput.Up && mouseDeltaY > 0) {
    20.             scrollDetected = true;
    21.         }
    22.         else if(Scroll == ScrollInput.Down && mouseDeltaY < 0) {
    23.             scrollDetected = true;
    24.         }
    25.  
    26.         FirstFrameScroll = !scrollDetected;
    27.  
    28.         return scrollDetected;
    29.     }
    30.  
    31.     private bool InputScrollFirstFrame() {
    32.         bool scrollDetected = false;
    33.  
    34.         if(FirstFrameScroll) {
    35.             scrollDetected = InputScroll();
    36.         }
    37.  
    38.         return scrollDetected;
    39.     }
    40.  
    41.     public void Rebind(KeyCode button, ScrollInput scroll) {
    42.         Button = button;
    43.         Scroll = scroll;
    44.     }
    45.  
    46.     public KeyCode Button { get => button; private set => button = value; }
    47.     public ScrollInput Scroll { get => scroll; private set => scroll = value; }
    48.  
    49.     public enum ScrollInput {
    50.         None,
    51.         Up,
    52.         Down,
    53.         Both
    54.     }
    55. }
    Code (CSharp):
    1. [CreateAssetMenu(menuName = "Player/Input/Input Map")]
    2. public class InputMap : ScriptableObject {
    3.     [SerializeField] private InputAction moveUp;
    4.     [SerializeField] private InputAction moveDown;
    5.     [SerializeField] private InputAction moveLeft;
    6.     [SerializeField] private InputAction moveRight;
    7.  
    8.     public InputAction MoveUp { get => moveUp; private set => moveUp = value; }
    9.     public InputAction MoveDown { get => moveDown; private set => moveDown = value; }
    10.     public InputAction MoveLeft { get => moveLeft; private set => moveLeft = value; }
    11.     public InputAction MoveRight { get => moveRight; private set => moveRight = value; }
    12. }
    Now whatever GameObject I want the player to control, I just need to attach a script with an InputMap reference:
    Code (CSharp):
    1. public class Example : MonoBehaviour {
    2.    [SerializeField] private InputMap inputMap;
    3. }
    Detecting inputs is as easy as this:
    Code (CSharp):
    1. public class Example : MonoBehaviour {
    2.    [SerializeField] private InputMap inputMap;
    3.  
    4.    void Update() {
    5.       if(inputMap.MoveUp.Started) {
    6.          //Started is the equivalent of Input.GetKeyDown() / Input.GetButtonDown()
    7.       }
    8.  
    9.       if(inputMap.MoveLeft.Held) {
    10.          //Held is the equivalent of Input.GetKey() / Input.GetButton()
    11.       }
    12.  
    13.       if(inputMap.MoveRight.Released) {
    14.          //Released is the equivalent of Input.GetKeyUp() / Input.GetButtonUp()
    15.       }
    16.    }
    17. }
    Rebinding inputs is as easy as this:
    Code (CSharp):
    1. public class Example : MonoBehaviour {
    2.    [SerializeField] private InputMap inputMap;
    3.  
    4.    void RebindExample() {
    5.       //The user now needs to press the up arrow key to move up.
    6.       inputMap.MoveUp.Rebind(KeyCode.UpArrow, InputAction.ScrollInput.None);
    7.  
    8.       //If the user REALLY wants to, they can do something crazy like this,
    9.       //where they can move down by pressing the L key or scrolling up with the scroll wheel.
    10.       inputMap.MoveDown.Rebind(KeyCode.L, InputAction.ScrollInput.Up);
    11.    }
    12. }
    And it's very scalable as well. Maybe later down the road, I add a feature where the player can input an action to perform some special ability. All I need to do is add a new InputAction to the InputMap and that's it:
    Code (CSharp):
    1. [CreateAssetMenu(menuName = "Player/Input/Input Map")]
    2. public class InputMap : ScriptableObject {
    3.     [SerializeField] private InputAction moveUp;
    4.     [SerializeField] private InputAction moveDown;
    5.     [SerializeField] private InputAction moveLeft;
    6.     [SerializeField] private InputAction moveRight;
    7.  
    8.     //New InputAction field added to set from the Unity inspector.
    9.     [SerializeField] private InputAction ability;
    10.  
    11.     public InputAction MoveUp { get => moveUp; private set => moveUp = value; }
    12.     public InputAction MoveDown { get => moveDown; private set => moveDown = value; }
    13.     public InputAction MoveLeft { get => moveLeft; private set => moveLeft = value; }
    14.     public InputAction MoveRight { get => moveRight; private set => moveRight = value; }
    15.  
    16.     //New InputAction property added.
    17.     public InputAction Ability { get => ability; private set => ability= value; }
    18. }
     
    Last edited: Aug 18, 2019