Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

[Solved] Can the new Input system be used without the Player Input Component?

Discussion in 'Input System' started by Coldsandwich189, Mar 29, 2020.

  1. Coldsandwich189

    Coldsandwich189

    Joined:
    Jul 25, 2018
    Posts:
    3
    I am learning from some old tutorials that do not use the player input component, but as I am trying for now I have no luck using only the generated C# scripting without using the Player Input Component.


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. public class Player_Input : MonoBehaviour
    7. {
    8.  
    9.     public GameObject unitSelected;
    10.  
    11.     public Controls controls;
    12.  
    13.     private void Awake()
    14.     {
    15.  
    16.         controls = new Controls();
    17.        
    18.     }
    19.  
    20.     private void OnEnable()
    21.     {
    22.  
    23.         controls.Enable();
    24.         controls.General.Attack.performed += ShootButton;
    25.         controls.General.Move.performed += MoveButton;
    26.  
    27.     }
    28.  
    29.     private void OnDisable()
    30.     {
    31.  
    32.         controls.General.Attack.performed -= ShootButton;
    33.         controls.General.Move.performed -= MoveButton;
    34.         controls.Disable();
    35.  
    36.     }
    37.  
    38.     public void ShootButton(InputAction.CallbackContext context)
    39.     {
    40.  
    41.         if (context.started && !context.performed)
    42.         {
    43.             //Shoot Here
    44.             Debug.Log("Shoot");
    45.         }
    46.  
    47.     }
    48.  
    49.     public void MoveButton(InputAction.CallbackContext context)
    50.     {
    51.  
    52.         if (context.started && !context.performed)
    53.         {
    54.             //Movement here
    55.             unitSelected.GetComponent<Movement_Controller>().Move();
    56.         }
    57.  
    58.     }
    59. }
    60.  
     
  2. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,278
    I could be mistaken, but is the issue not that you're registering for the "performed" callbacks, but then in your handlers you're checking "!context.performed"?
     
  3. Coldsandwich189

    Coldsandwich189

    Joined:
    Jul 25, 2018
    Posts:
    3
    I am assuming you are saying this

    1. if (context.started && !context.performed)
    2. {
    3. //Shoot Here
    4. Debug.Log("Shoot");
    5. }
    I put that there because for some reason when I use the component to make the input system work it call the function 4 times. Adding the ifs prevented it.
     
  4. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,278
    Ok, but look at how you're preventing it. I strongly suspect you're filtering out the wrong calls.
     
    Coldsandwich189 likes this.
  5. Coldsandwich189

    Coldsandwich189

    Joined:
    Jul 25, 2018
    Posts:
    3
    Thanks it works now, it is the if's statements. I think I should not have left them there because I change into the component midway and then came back to try using scripts again. Thanks again!
     
  6. GilbertoBitt

    GilbertoBitt

    Joined:
    May 27, 2013
    Posts:
    111
    how we can use the c# generated class this way for local multiplayer?
     
  7. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Each generated class is an IInputActionCollection. Each collection of actions will by default enable all bindings and grab controls from all available devices (i.e. from InputSystem.devices). This behavior can be controlled through two properties: "devices" and "bindingMask".

    "devices" controls which devices are used by the actions in that collection. By default it's not set which leads to the "ok, then I'm just going to grab from InputSystem.devices" behavior. You can set this property at any time and repeatedly and the actions will update.

    "bindingMask" controls which bindings are used and which are ignored. Only bindings that match the mask will get resolved to controls, the rest will just be skipped. By default, there is no mask which leads to "ok, then I'm just going to enable everything". You can set this property at any time to reflect which bindings you want active at any time.

    So.... long story short, you can set up multiplayer by setting these two properties.

    Code (CSharp):
    1. // Let's assume you have a generated C# class called "MyControls".
    2. // Let's create two instances of this and set one up for gamepad
    3. // and one up for keyboard&mouse. Let's assume there is a control
    4. // scheme called "Gamepad" and another called "KeyboardMouse".
    5.  
    6. // P1 gets gamepad.
    7. var p1Controls = new MyControls();
    8. p1Controls.devices = new[] { Gamepad.all[0] };
    9. p1Controls.bindingMask = InputBinding.MaskByGroup("Gamepad");
    10. p1Controls.Enable();
    11.  
    12. // P2 gets keyboard&mouse.
    13. var p2Controls = new MyControls();
    14. p2Controls.devices = new[] { Keyboard.current, Mouse.current };
    15. p2Controls.bindingMask = InputBinding.MaskByGroup("KeyboardMouse");
    16. p2Controls.Enable();
    So with this, you have two independent MyControls input setups.

    If you want to take this one step further, you can leave much of the mechanics to InputUser, which is what PlayerInput uses underneath.

    Code (CSharp):
    1.  
    2. // P1 gets gamepad.
    3. var p1Controls = new MyControls();
    4. var p1User = InputUser.PerformPairingWithDevice(gamepad.all[0]);
    5. p1User.AssociateActionsWithUser(p1Controls);
    6. p1User.ActivateControlScheme("Gamepad");
    7. p1Controls.Enable();
    8.  
    9. // P2 gets keyboard&mouse.
    10. var p2Controls = new MyControls();
    11. var p2User = InputUser.PerformPairingWithDevice(Keyboard.current);
    12. InputUser.PerformPairingWithDevice(Mouse.current, user: p2User);
    13. p2User.AssociateActionsWithUser(p2Controls);
    14. p2User.ActivateControlScheme("KeyboardMouse");
    15. p2Controls.Enable();
    But it's not necessary. A working multiplayer setup can be achieved with just the generated C# class alone.
     
  8. GilbertoBitt

    GilbertoBitt

    Joined:
    May 27, 2013
    Posts:
    111
    thanks, @Rene-Damm the way of doing using the Player Input manager and manually spawning player on join using the InputUser or Player Input is for me the better option. thanks so much.
     
  9. TJHeuvel-net

    TJHeuvel-net

    Joined:
    Jul 31, 2012
    Posts:
    785
    The input system is now at version 1.0.0, why do i still have to find some forum post for essential documentation?

    Honestly the PlayerInputManager is making things more confusing rather than helping out, i cant understand why it was added. It fits a very specific case, where players join in at any moment and might have split screen, and even that not very well. Any other form of having local multiplayer, such as pre-selecting input devices in a menu, seems utterly unsupported.
     
  10. Reillo

    Reillo

    Joined:
    Feb 11, 2019
    Posts:
    2
    Hi, I've just tried to implement your solution and it throws a memory leak error that seems to be coming from the user.ActivateControlScheme("Gamepad"); line: "A native collection has not been disposed, resulting in a memory leak". Is there some extra line to force it to dispose of the native collection?
     
  11. Reillo

    Reillo

    Joined:
    Feb 11, 2019
    Posts:
    2
    Oh and if it's of any help the error only registers starting from the second play after compiling the script for whatever reason (even if the script itself wasn't changed), so the first play after returning to unity from visual studio never registers an error.
     
  12. UncleAlias

    UncleAlias

    Joined:
    Aug 18, 2017
    Posts:
    27
    Hi, I'm trying to figure out how to get this information from the PlayerInput module. Maybe something like this:

    Code (csharp):
    1.  
    2. // you have a reference to the PlayerInput module called p1Input
    3. var p1Controls = new MyControls();
    4. p1Controls.devices = p1Input.devices;
    5. p1Controls.bindingMask = InputBinding.MaskByGroup("p1Input.controlScheme");
    6.  
    It would be nice if you could just pass an InputControlScheme struct to the script since that would have all the necessary information, right? Or couldn't it just look for a PlayerInput module?