Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Multiple control schemes or actions

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

  1. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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:
    237
    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
    M4R5 likes this.
  4. Rene-Damm

    Rene-Damm

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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.
     
    Fernan_ and PPLorux like this.
  5. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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
    JDeyby, barisdincer and Fernan_ like this.
  7. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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.
     
    Meatloaf4 and Biggerandreas like this.
  9. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    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. MoeAyyad

    MoeAyyad

    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:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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. MoeAyyad

    MoeAyyad

    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:
    237
    @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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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:
    237
    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:
    237
    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:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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:
    237
    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:
    237
    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

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    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:
    237
    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:
    237
    @Rene-Damm Hey, any news on what's going on ?
     
  29. Jichaels

    Jichaels

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

    neil89

    Joined:
    Sep 30, 2013
    Posts:
    7
    Hey! This have been so far the best help found in order to make a local multi player game.

    I've been digging for two weeks how new input system is working, since I couldn't make a local mulitplayer in last Global Game Jam using old input system. I was hoping this time would be a good opportunity to get it using new input system. Maybe the rebinding project included in 2019.3 can do the trick?

    My problem is, as @Jichaels asked some time ago, several ways to do things. At this time, I got gamepad and keyboard working but both of them affects all the players in game, at the same time. I can't get one device related to each player. Is PlayerInputManager ready to use at this time? What's the way to do things in order to get local multiplayer, subscribing
    .inputactions
    events, or using
    <Scheme>.<Action>.performed/started
    ?

    Maybe @Rene-Damm can help us! Lots of thanks in advance.
     
  31. SinginKid

    SinginKid

    Joined:
    Apr 10, 2020
    Posts:
    1
    Agreed with neil, it specifically happens to me with a 1D Axis. Curious if you have had issues with your methods being called three times from code. Found the fix for it but its pretty janky atm. Also trying to apply current multiple schemes to one keyboard. While one fully functions the other does not. Not sure what is going on. I just want seperate schemes for the same keyboard
     
  32. lejean

    lejean

    Joined:
    Jul 4, 2013
    Posts:
    392
    Is it possible to make the mouse and gamepad work together even when play coop and using playerinput?

    I have some buttons in my UI for example that open up social media pages but the buttons don't seem to react to the mouse when I'm playing with the gamepad.

    I have a controller scheme for both keyboard and gamepad but I enabled mouse pointer for both gamepad and keyboard in the scheme but that doesn't seem to do anything.
     
  33. VR_Junkie

    VR_Junkie

    Joined:
    Nov 26, 2016
    Posts:
    77
    Hello, I am using an oculus and have the control scheme set to "generic xr controller" (the default). When I plug my oculus into my computer it still uses the PC control scheme. If I add the PC binding to my oculus actions the oculus starts working but that's not what I want to happen (as then my keyboard AND my headset would both have control over the game). How do I choose which control scheme I want to use with code? Iam using generated C# wrapper for the actions
     
    Last edited: Mar 27, 2021
    Deleted User likes this.
  34. YEX_

    YEX_

    Joined:
    Dec 26, 2017
    Posts:
    1
    How do you check which control scheme (not necessarily the device) is being used atm?
     
  35. M4R5

    M4R5

    Joined:
    Apr 11, 2013
    Posts:
    33
    This is the way a Unity support thread ends--
    not with a bang but a whimper.
     
  36. Un4GivNX

    Un4GivNX

    Joined:
    Oct 18, 2020
    Posts:
    6
    Having the same problem, only 1 input user + 3 "available" input devices. The control scheme doesn't switch. Waiting for more guidance.
     
  37. CBHM

    CBHM

    Joined:
    Feb 12, 2019
    Posts:
    32
    How can I restrict the bindings to a specific device,
    The problem I am having is the game supports keyboard + mouse for desktop users, and Vive Pro for VR users, I have two control schemes set up one for Desktop and one for Vive.
    I switch the control scheme based on the device connected - when they select VR mode and Vive gets connected the control scheme switched to the Vive control scheme. The problem is they are still able to use the keyboard and mouse to move the character around which I don't want.

    I am not using PlayerInput class