Search Unity

Question Radial aim control in 2D game for both mouse and gamepad

Discussion in 'Input System' started by EmmetOT, Jul 29, 2021.

  1. EmmetOT

    EmmetOT

    Joined:
    Apr 25, 2016
    Posts:
    44
    I'm using the new input system and mostly liking it so far, however I'm trying to make a simple 2D shooter in which the player can aim in a radius around themselves.

    With mouse, this involves pointing at a position on screen, which is then translated into a direction relative to the player's position. With gamepad, it's simply the rotation of the right stick.

    For my input system workflow I like building it to a C# class and just using it with callbacks, or checking the actions in update.
    upload_2021-7-29_20-29-26.png

    I can get one of the input schemes to work but not both. This is because the mouse input requires some degree of 'processing' but the gamepad input is essentially raw. I'm wondering what I have to do to make the input system produce the appropriate direction input for both schemes. I can see there's a 'radius' option for mouse input which seems like what I want, but it simply gives (0, 0).

    Here is the code I have for handling the input, which works correctly for the mouse input but obviously just gives nonsense for the gamepad.


    Code (CSharp):
    1.  
    2.         // called from the update loop
    3.         private void UpdateAimInput()
    4.         {
    5.             Vector2 val = m_input.Player.Aim.ReadValue<Vector2>();
    6.             Vector2 target = Camera.main.ScreenToWorldPoint(new Vector3(val.x, val.y, -Camera.main.transform.position.z));
    7.  
    8.             m_aimInput = (target - (Vector2)transform.position).normalized;
    9.         }
    10.  
    Here are some solutions I'd expect:

    1) Maybe I'm using radius wrong? I can't find any documentation about this anywhere.
    2) If I had some way to differentiate the control source (mouse v gamepad) this would be a piece of cake. I can see there are ways, but they involve string comparisons and are specific to my brand of controller. For example,
    m_input.Player.Aim.activeControl.device.displayName
    gives "Xbox Controller" which obviously isn't ideal.
    3) Maybe there's some way to write a custom processor in the input asset. This would be really useful.
     
  2. Radlas

    Radlas

    Joined:
    May 25, 2020
    Posts:
    1
    Code (CSharp):
    1.  
    2. var inputLookDir = inputActionLook.ReadValue<Vector2>();
    3.         if (playerInput.currentControlScheme.Equals("Gamepad"))
    4.             inputLookDir = inputLookDir.normalized;
    5.         else
    6.             inputLookDir = (inputLookDir - new Vector2(Screen.width/2, Screen.height/2)).normalized;
    7.  
    Since reading a Gamepad Stick input will result in a Vector2 with values clamped between -1 and 1, and that's what I desired in my project, I do an additional processing step to convert the Position input of the mouse.
    I check the active control scheme, and if its not Gamepad, I convert the mouse position to a usable vector where the 0,0 is the center of the Screen.
     
  3. EmmetOT

    EmmetOT

    Joined:
    Apr 25, 2016
    Posts:
    44
    Unfortunately, since I'm using a generated C# class, I have no access to "currentControlScheme". For some silly reason...

    Thanks for the help, though!
     
  4. badi-haki

    badi-haki

    Joined:
    May 24, 2016
    Posts:
    2
    Having the exact same issue, you ever find a solution?
     
  5. SMT5015

    SMT5015

    Joined:
    Apr 5, 2021
    Posts:
    53
    When you receive an InputAction.CallbackContext struct in your subscribed methods, it has a field "control" of type InputControl, which tells you from where the action was triggered. And it has a property "device" of type InputDevice. You can process input depending on the type of device, doing what you did if it was mouse and something else if it was gamepad or whatever.

    Or, since you probably don't want to compare types for such frequent action, you can retrieve a path for an InputBinding inside the action and use static class InputControlPath to check if it matches the control.
     
    Last edited: Feb 7, 2023