Search Unity

Multiple control schemes or actions

Discussion in 'New Input System' started by Jichaels, Aug 14, 2019.

  1. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Hi everyone,

    I'm currently playing around with the new Input system and I've a (probably silly) question.

    What is the difference between having 1 control scheme that register Keyboard/Gamepad, and 1 control scheme for keyboard, 1 control scheme for gamepad ?

    upload_2019-8-14_10-59-51.png

    Here I've only one control scheme, that get input from both. Is it wrong from doing so ?
     
  2. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Basically all depends on what you're trying to achieve. In the case of having one single combined control scheme with gamepad+keyboard, you'll likely not need a control scheme at all.

    Control schemes are only really relevant if you want to separate multiple different means of controlling your game/app from each other such that they are mutually exclusive and such that you can know which one is active at any one time (e.g. to display control hints).

    So in effect, the intention for having two control schemes, one for keyboard and one for gamepad, would be that keyboard input is not meant to be used concurrently with gamepad input. While the keyboard bindings are active, the gamepad bindings will not be. If both are in the same control scheme, however, they will concurrently be active side by side. This means that, for example, if the player has both a keyboard and a gamepad connected, the system will establish a connection to both even if the player only uses one of them.

    To conclude this and make it slightly more confusing, though, worth mentioning that most of the APIs do not respect control schemes except when being told to. PlayerInput is different. If there are control schemes present in the asset, it will use and respect them. However, most of the other, lower level APIs will blindly operate on all bindings present in the asset except if restricted to specific ones.
     
  3. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Ok thanks now I'm even more lost :D

    So let's say I want to make a local coop game (I'm following a course that use the old input system and wanted to use the new one), that you can play with either keyboard or gamepad, what should I do ?

    As players will be able to play on the keyboard while the other player can play on the gamepad, or maybe two gamepad or two player on the same keyboard (wasd/arrow for exemple).

    Should I create one "Input actions" per player ? That looks complicated for something that should be rather simple.
    Or should I create everything on one Input Actions, and handle by code what player to move/etc. based on what was pressed ?

    I couldn't find any doc about rebinding at runtime aswell (and it's really easy with the old input system). The doc on github is messy and some parts are missing / outdated, is there a place where I can look into the doc ?

    Thanks a lot !
     
    Last edited: Aug 20, 2019
  4. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Separate control schemes for the two so that one or more players can use gamepads and another player can use the keyboard. If you put both keyboard and gamepad in the same control scheme, the first player will grab both the keyboard *and* a gamepad as a result. Means that no other player can use that gamepad even if the player is actually playing with the keyboard.

    One .inputactions asset with multiple control schemes. PlayerInput will duplicate the actions as needed and will pick control schemes and assign devices.

    There isn't a ready-made UI equivalent to the old Unity startup dialog yet. There's APIs (mainly PerformInteractiveRebinding()) but they require scripting on your end to hook up to your API. Documentation is coming shortly.
     
  5. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    But what if two players plays on the same keyboard ? Like one using WASD/Space and the other one using Arrows/whatever ? Is it not possible using this new input system ?


    Oh ok that's cool, I'll try this. Didn't think you could "duplicate"


    I wasn't talking about the "startup dialog" that I really don't like and never set it to show up anyway. What I use in my projects is a static class that will load controls from json, assign corresponding keycode to static variables, that I can modify at run time with a foreach loop that returns me wich key was pressed.


    Thanks again
     
  6. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Yes, with a bit of manual scripting as PlayerInput on its own will not assign the same device to multiple players. Create two keyboard controls schemes and then either manually pair devices at runtime or create the players manually through PlayerInput.Instantiate

    Code (CSharp):
    1. var player1 = PlayerInput.Instantiate(playerPrefab, controlScheme: "WASDKeyboard", device: Keyboard.current);
    2. var player2 = PlayerInput.Instantiate(playerPrefab, controlScheme: "ArrowsKeyboard", device: Keyboard.current);
    You can override the effective path on any binding non-destructively at runtime.

    Code (CSharp):
    1. // Let's say the actions you have on PlayerInput.actions contain
    2. // a fire action and you want to change the binding for the
    3. // WASDKeyboard scheme from space to to left control.
    4. var fireAction = playerInput.actions["gameplay/fire"];
    5. fireAction.ApplyBindingOverride(new InputBinding
    6. {
    7.     groups = "WASDKeyboard",
    8.     overridePath = "<Keyboard>/leftCtrl"
    9. });
    If you want to let the player choose the target binding as part of a rebinding UI

    Code (CSharp):
    1. var rebind = fireAction.PerformInteractiveRebinding();
    2.  
    3. // If you want to restrict the rebind to a particular control scheme
    4. rebind.WithBindingGroup("WASDKeyboard");
    5.  
    6. // Initiate rebind.
    7. rebind.Start();
     
    Last edited: Aug 14, 2019
  7. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Oh, ok that's incredibly helpful !

    The main "problem" I have with this new input system is that there is 2-3-4+ possible ways of doing the same thing, which is extremely confusing (that plus the lack of documentation but it'll come out) !

    For example, in the sample that you can download from the package manager, there is 4 demos, each achieving the exact same thing, but done in different ways :confused:

    I'm almost set up now thought, but I still have some questions remaining if you don't mind :

    1- I'm trying out the PlayerInputManager, which looks really cool, but it hides everything. For example, I can register to the OnPlayerJoined() event, but I'd like to be able to know/modify what a "player joining" is doing. For example, Instantiating the prefab myself at the time I want... etc. Is that possible ? Is there documentation about what is PlayerInputManager doing behind the scenes ?

    2- So if I understood correctly, if I want to have two players on the same device (Keyboard in this case), I have to do everything manually (Instantiating the players and whatnot). So if it is not possible to modify PlayerInputManager, I can't use it because it won't work for my case ?

    3- If I want to have two players on the same device, I need to have at least two controls scheme ? Or can I simply have two actions map / two actions ?

    4- More of performance related question, but is there any differences/benefits from using SendMessage/UnityEvents ? For me it (again) look like two different ways of doing the same thing, so confusing :(

    Thanks for your time
     
  8. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Can definitely see how that is confusing though hopefully good documentation will make it less so.

    Overall, there being several ways to do things is intentional. With the breadth of use cases that Unity projects have these days, having only one way to do something is often not feasible anymore. For that reason, the system is layered. Higher-level layers abstract more and strive to make things easy to get started while lower-level layers open the system up to heavy customization.

    PlayerInput is also a good example, I think. It has generally proven a very easy and quick start into the system but what it can do is limited to a specific set of use cases. If PlayerInput was the only way, the new system would quickly prove limiting for many users just like the old one did. And if there wasn't such a thing as PlayerInput, the system would have a high barrier of entry for new users.

    ATM that's still missing. PlayerInputManager needs more work to open up what it does to customization. It'll come. Especially the ability to take over player instantiation and not just have it instantiate a prefab is definitely needed.

    Yes, ATM for split-keyboard setups, you will not be able to use PlayerInputManager at this point.

    Neither is necessary. You can have arbitrary many players all using the same single control scheme and same actions as long as there is one set of devices required by the control scheme available for each player.

    Control schemes differentiate means to control your game (keyboard&mouse vs gamepad vs touch vs whatever), not players. Each control scheme is a statement like "given these devices here, this is how you control the game".

    SendMessage/BroadcastMessage is slower and more brittle but is easier to setup. In general, adequate for prototyping but not more.

    Unity Events are more performant as the connection between sender and receiver is made directly.
     
    Biggerandreas likes this.
  9. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Trying to get everything working. Looking good so far, I hope I'll be able to do what I want :p

    Thanks a lot !
     
  10. MohdAyyad

    MohdAyyad

    Joined:
    Sep 11, 2018
    Posts:
    2
    Hi,

    I'm a little confused on how to differentiate between control schemes. I have setup two control schemes for the same action map: one is a keyboard and mouse action map, and another one for xbox controllers. The idea is that I want to use the same code and action map for multiple players. I added a PlayerInput component to the player prefab, and it seems that choosing a control scheme really doesn't matter as I can still control the player using both keyborad and gamepad.

    upload_2019-8-22_17-29-30.png

    upload_2019-8-22_17-29-55.png

    upload_2019-8-22_17-30-21.png


    In the player's scrip I check for the value of Move to move the player's object:

    Code (CSharp):
    1.    if(Mathf.Abs(controls.Player.Move.ReadValue<float>()) >0.0f)
    2.         {
    3.             Move(controls.Player.Move.ReadValue<float>());
    4.         }
    What am I missing?

    Thanks
     
  11. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    From what I understood, if you want to go that way (with PlayerInput), you don't have to call controls.Player.Move yourself. Create a function like OnMove(CallbackContext ctx), and assign that in your player input OnMove (on the editor, set Invoke UnityEvent, and you should see it).

    At least that's how I do it
     
  12. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    ATM there's hardcoded logic in PlayerInput that enables auto-switching of control schemes when there is only a single player. The assumption is that in a single-player game, the player is meant to be allowed to use every available device whereas in a local multi-player game, the player is restricted to just his or her assigned devices.

    The auto-switching detects when a device is used that doesn't belong to the current control scheme but is usable with another one and then automatically switches the control scheme on the player.

    There should probably be a bool property that allows you to explicitly toggle auto-switching in single-player on and off.
     
  13. MohdAyyad

    MohdAyyad

    Joined:
    Sep 11, 2018
    Posts:
    2

    Yes, this works if you want a function to be called back when an a certain action in a certain action map is triggered. It doesn't help, however, with the distinguishing between input devices :( Unless I'm missing something.


    Yeah, I get it. It's actually a pretty smart assumption. Sadly, I could not find the bool you're talking about, I'm guessing it's gonna be editable in a future patch? So far, the only way I was able to make two objects be controlled using two different input devices while preventing the input devices from controlling the other object (so P1 can only be controlled using a keyboard, and P2 can only be controlled using a gamepad) was by creating two action maps, but that seems too much of hassle since I need to duplicate code lines to make sure both action maps can invoke all the mutual functions between the two player objects.

    Thanks
     
    GabrielSants likes this.
  14. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    @Rene-Damm

    Hey !

    I now have a problem I just didn't see before as I mostly tested using my gamepad : The player input manager create a player for both Mouse and keyboard separately o_O
    Is there any way of telling it to "join" both ? I can already prevent the mouse player to play in the OnPlayerJoined event, but then I can't get any inputs from the mouse for the "keyboard player".

    Thanks again
     
  15. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Yes, should be.

    Wait, I think I missed something here and thus misunderstood your actual problem. Looking at your original post, you are mixing PlayerInput along with a generated C# wrapper for the actions. This would explain why control schemes aren't working right for you.

    We probably need to improve documentation here and make it clearer that there's no association between the two features. If you generate a C# wrapper for an .inputactions file, you get a self-contained means of using the actions. There's no connection to the stuff in PlayerInput even if they share the same source .inputactions.

    Your problem is probably fixed by getting rid of the "controls" property. Check the PlayerInput documentation for how to respond to actions triggered by PlayerInput.

    Putting the mouse bindings in the same control scheme and adding the mouse device to the control scheme should do the trick.

    Basically, each control scheme needs to mention all the devices that go together to form one *complete* way of controlling your game.
     
  16. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    But I'm not using control schemes at all ? I already have both keyboard AND mouse AND gamepad actions in the action map.

    Also, when click&draging with the mouse when I'm in game, I get CRAZY cpu usage. This is like a one second drag :
     

    Attached Files:

  17. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Ok, fixed the problem concerning CPU. Apparently Player Input Manager try/instantiate a new player each frame where it gets input, so as I was destroying it on OnPlayerJoined, it tried to instantiate it again, and again...

    Still have no clue how I should go about joining input and keyboard as "one device".

    Edit : more problems, as the PlayerInputManager still try to add a new player, even if I just ignore everything comming from it, all the PlayerInput.user.id are messed up :(
     
    Last edited: Aug 27, 2019
  18. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Well, refractored everything to use control schemes instead of what I was doing, and I'll try to find a way to maybe let the player switch between control schemes if there is no other player.

    Thanks anyway, I may post a build here when I pull everything together for people that would want to see how it is
     
  19. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    The system will do that automatically. If there is only a single PlayerInput enabled, that player will automatically switch between available control schemes when devices not paired to but compatible with the player's actions are used. If there are multiple PlayerInputs enabled, this behavior is disabled automatically.
     
  20. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Then I can't get it to work :(

    As soon as I hit a button in another control scheme, it still instantiate a new Player. What could be wrong ?
    Maybe it's the joinin behaviour of PlayerInputManager ? It's set to Join when button is pressed. Should I go with join player manually ? But then I'll have to do everything myself....
     
  21. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Depends on your game. If a new player can join at any point in the game on any supported device, then yes, automatic control-scheme switching can't be used (still need a bool to be able to toggle it off; on the TODO list).

    In many games this is solved with an explicit lobby and/or by having single and multiplayer go through different paths in the menu. With a lobby (which may or may not be its own separate screen), you'd disable joining on the PlayerInputManager as soon as all players have joined. When going through different menu paths, you'd never enable joining on the single-player path but enable it in the multiplayer path.

    If you have a point in your game where gameplay starts and joining is no longer possible, solving this can be as simple as

    Code (CSharp):
    1. PlayerInputManager.instance.DisableJoining();
     
  22. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Ok so I do have a lobby, and people can't join after the game started.

    When I start the game, spawn characters... etc, I do
    Code (CSharp):
    1. PlayerInputManager.Instance.DisableJoining();
    but it still doesn't switch between control schemes...

    On the PlayerInput, there is only the first device used when PlayerInputManager create the player.

    If I try to switch control schemes myself, what I'm trying to do is
    Code (CSharp):
    1. Players[0].playerInput.user.ActivateControlScheme(Players[0].playerInput.controlScheme == "Gamepad" ? "MouseKeyboard" : "Gamepad");
    It does work (or at least it changes on the player), but as the device does not change (and I don't find a way to do it myself, neither on PlayerInput or InputUser) it doesn't do anything and I can't control anything anymore.

    I'm going crazy :(
     

    Attached Files:

  23. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Ok, if there's only a single PlayerInput (i.e. single user in the debugger) in the game and you actuate a control on a device not paired to that one PlayerInput but there's a control scheme for that device and with bindings for it, but the system still doesn't switch... that sounds like a legit bug.

    Could you attach your .inputactions file and also show me what the input debugger (Window >> Analysis >> Input Debugger) looks like in the "Users" section? Plus, which control are you using on which device that isn't leading to a switch?

    Sorry for all the hiccups. As we are discovering, PlayerInput still provides plenty opportunity for things to not quite go as expected... :)
     
  24. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Here you go. Really hope it's a bug because I'm feeling really stupid right now.

    I don't even know why I'm losing so much time and mental sanity for a local coop game, who plays that anyway lol

    If I join with the gamepad, then any input coming from keyboard are ignored, and vice versa if there is only one player.
    Works as expected with multiple players (one on gamepad / one on mouse/keyboard).
     

    Attached Files:

  25. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Btw, it was not (only) the create/destroy of new player that was the problem to the CPU usage.

    I still get INSANE CPU usage / GC calls when clicking and draging the mouse. Doing it for only a second cause everything to blow up and Unity doesn't answer for a good 2mn.

    I don't think it's my script causing that, as I'm only doing a print(callBackContext) for now.

    Could it be that my mouse input is not set properly ? Maybe it's triggered way too much (but even then, it's crazy stupid how bad it gets). I only have :

    Action type : Value
    Control type : Vector2
    Path : delta [Mouse]

    no interactions, no processors

    Edit: Ok it IS the print call that blows up everything, what the F*** ? It's not a Debug.Log, which I know is somewhat expensive. Why would the mouse delta be triggered hundreds of time each frame ? Is there any reasons you would want more than one each frame ?
     
  26. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    616
    Thank you for the files. I'll have a look

    MonoBehaviour.print is identical to Debug.Log which captures a full stack trace on every call and does expensive additional processing in the editor console view.

    Mice are generally sampled at high frequency. The system captures and processes input at the rate it's being produced.
     
  27. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Oh ok, good to know. So should I limit myself the rate of input coming from the mouse delta (like only adding the value in a var, and doing actual translation/rotation/whatever once per frame in Update()) ?

    Thanks for your time, hopefully you are really reactive, I would've went crazy :D


    Edit : I'm still trying things (on a new project), and I can't get the Mouse delta/x to trigger anything ? Works fine with the gamepad rightstick, but delta/x is never triggering anything. Any idea ? I could use just mouse delta as a vector2 and only get the x value, but that can't be the right way
     

    Attached Files:

    Last edited: Aug 28, 2019
  28. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    @Rene-Damm Hey, any news on what's going on ?
     
  29. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    42
    Still not found a solution to switch between control scheme automatically (even when there is only one playerInput) :(