Search Unity

Input Mapper

Discussion in 'Assets and Asset Store' started by winxalex, Jun 29, 2014.

  1. winxalex

    winxalex

    Joined:
    Jun 29, 2014
    Posts:
    166
    Unity Input Manager pain is lasting for years. On Unity site you can find request on the forum for InputManager programmatic access dating from 2004, and some new from 2014. Futile.







    Its good they are planning to :). Now see the date 2009 of feedback, then see your computer date. Calculate difference in years. Ultimate Game Development with state of the art InputManager system :D.



    Problems:



    Input handling is beast overall taken. There difference in how diffrent OSes handle input. Even same controller is attached meaning identical hardware and communication protocol different OSes would handle differently cos of at least byte order. Then difference come from different drivers used in different OS so for example OSX recognize XBOX360 Wireless controller POV as 4 buttons and WIN as 2 Axes. In same OS you can have multiply default handling ways like Winmm and DInput,XInput in Windows. Even in same OS but different version and same handling way could have differences(ex. Winmm doesn't recognize sliders/triggers in WIN7 and have no problem in WIN8). On top all that come problems with Unity mono threading when add/remove device notification and input are async interrupt based.







    1) Editor and Ingame input controller mapping.

    Unity Input Class works only in Play mode so you are left to blindly mapping inside Input Manager tree view. Changing mapping later need game restart.

    2) Handling input in code based on states/tag abstracting real input.

    Some sort of abstraction is done thru InputManager well known "Horizontal" and "Vertical", but that abstraction is still bonded to axes and buttons and not to actions/states of the game(one of those might be AnimateStates of Mecanima).



    3) Saving and restoring user preferences

    PlayerPref might do the trick if filesize is not bigger then 1 megabyte. You can use .asset or also load InputManager.asset during runtime and save but might involve extra efforts when WebPlayer or Droid is target.

    File type that can be readable by humans and machines, and easy exchangeable( players can exchange their game settings) between them might be XML.



    4) Recognize positive and negative part of the axis.

    Unity recognize Axis as whole part and gives value 1 <--- (-1) ---> 1. It is expected to gives value from 1<---- (0) ----> -1, so turning left/right on wheel input controller or joystick push/pull forward/backward can be achieved, trigger shooting rapid fire... .



    5) OS independent driver and easy expansion with drivers supporting other devices and special properties

    Unity internal input handler might not recognize the controller or it will identify layout in different system differently and would not offer support of device extra features like force feedback, IR pointer, accelerators, gyros ...of modern input controllers. So instead of use pluggin-paid OS dependent drivers, seem much better OS dependent HID interfaces with OS independent pluggable drivers.



    6) Handling input axis and buttons as digital or analog

    In Unity thru Input class you can handle axes only as analog and buttons as analog/digital. Its handy to have axes as digital events UP, DOWN , HOLD...



    7) Create combination of inputs that would trigger action/state

    Unity doesn't offer out of the box combining input actions like 2 keys in row, button press and axis move, ....like in fighting game scenario 2 times joystick left + fire (Mustafa kick Cadillacs and Dinosaurs)



    8) Handling inputs by events

    Unity is planned as single threaded getting out of the way of multi-threading headache. Complex input handling require input events as Update function got overcrowded. This involve multi-threading and need extra attention towards synchronization with Unity main thread.





    9) Plug and play instead of plug and pray.

    Attach or remove controllers while game is running and continue playing. Somekind of add/remove notification can be done with tracking of number of joystickNames thru Input.GetJoystickNames() but when 2 or more joysticks are of same type that way having same names distinction isn't possible. Also order of names in list is might change after reattaching same device for ex. previous Joy1 become Joy4 (hack *). I noticed that some controllers(XBOX wireless under OSX) are hard bind to Joystick# no matter position in GetJoystickNames list.









    10) Profiles - Layouts

    Show user friendly appearance of mapped input like Left Stick X, Bumper, Forward, Triangle, Square,....instead of Joystick1Button15, Joystick3Axis12... Switch profiles by assigning different controller to different player.

    *Entries for every Joystick#+Buttons# (Joystick1Button1,...Joystick2Button2... inside InputManager multiplied by factor for variation with keys and settings.









    Input Mapper system try to address above issues.















    1) Ingame input controller mapping.

    Input Mapper allows you easily to map game controller input to custom states.













    2) Handling input in code based on states/tag abstracting real input.

    InputMapper API looks very similar to Unity API's, but they offer abstraction on 2 levels. First you not program with real inputs like KeyCode.Q or Joystick1Button99, but with states which also allows player to map different input to same action state.




    //atOnce (default=false)
    //Function returns true when combination pressed in sequence If set to true function return true
    //when all keys/buttons in combination are pressed.Modifier like behaviour (LeftCtrl(-)+B)
    Code (CSharp):
    1. bool bCombo = (InputManager.GetInput((int)States.Jump,InputPlayer.Player.Player0,atOnce
    2. ));


    You are handling input of State.Jump, no matter what Player have mapped to that input, no matter is KeyCode.Q or Joystick1Button99 or something else.



    3) Saving and restoring user preferences

    Saving would export your settings to .xml or .bin file and States.cs will be generated containing enum of your mapped states.



    Code (CSharp):
    1. public enum States:int{
    2. Wave=1397315813,
    3. MyCustomState=-1624475888,
    4.  
    5. Now you can forget about:
    6.  
    7. //  static int idleState = Animator.StringToHash("Base Layer.Idle");
    8. //  static int locoState = Animator.StringToHash("Base Layer.Locomotion");
    as we are thought in Unity tutorials, but you can use States.[some state].





    4) Recognize positive and negative part of the axis.

    System recognize Forward,Backward,Left,Right of POV axis and Positive/Negative of normal axes.

    This is useful when you are using your joy stick as button.




    InputCode.Joystick2AxisPositive.SINGLE

    InputCode.Joystick2AxisNegative.LONG




    Intent is states not to be addressed as string as in above example given just for clarification. Use Enums!



    5) OS independent driver and easy expansion with drivers supporting other devices and special properties

    I understood Unity couldn't support all game devices but some system that allows simple binding of specific driver might be good idea. Why? All AAA Games provide list of top controllers used and tested with their game and they would work out of the box. The owner of rest controllers might relay on manufacturer or OS.



    (Yeah they have pluggins.....).

    So instead building pluggins for all OSes, you use InputMapper system built-in mini HID interface systems for (Win,Web,Droid and OSX) and OS independent driver. (Yes you can make C driver cross compile to anything...but....discussion need lot of effort).



    If specific driver is found for your device it would be handled by it:



    Code (CSharp):
    1.  
    2. //supporting devices with custom drivers
    3.    InputManager.AddDriver(new XInputDriver());
    If there is no specific driver for device default driver (WinMMDriver for Win and OSXDriver for OSX) would try to handle device.



    You can use UnityDriver as default driver having default Unity handling functionality, and still handle specific devices with specific drivers.



    InputManager.hidInterface.defaultDriver=new UnityDriver());//

    Swap your InputManger.asset with InputManager.asset from github source code.


    Warring:Unity doesn't make distinction between triggers/axis/poitOfView and doesn't make controller distinction as multiply instances of same type have same name and can hard code index of devices no matter position in GetJoystickNames list.



    Specific driver implementation guidelines:


    Your implementation of custom device driver had 2 entry points that need implementation:


    (1)public IJoystickDevice ResolveDevice(IHIDDeviceInfo info)...

    (2)public void Update(IJoystickDevice joystick)...



    ResolveDevice where HIDInterface provide device info from the OS, you can check VID and PID to decide to handle and init device properties and structures, or not returning null, and Update function to query device by use of provided Read/Write methods methods and fill the JoystickDevice structures, so can be accessed by InputManager. Scare about handling few bytes??? :)

    Originally OS implementation of ResolveDevice point is by using Report HID Page from device description, but that restrict using devices that aren't planned to work with that OS, like Wiimote,Xbox Gamepad...

    In Input Mapper you need simply to extend JoystickDevice Class, which already contains some basic functionality supporting axes and buttons, by adding specialized properties of device you are planning to support.

    Update point is synchronization point with Unity. System use high level synch and async ReadXXX methods and return buffered byte array. What each of bytes means is easy to decipher as there are many web sites about any devices. Developer task is to fill JoystickDevice structure with values processed from byte array returned.

    Write methods are used for setup the device...like light leds, start FFD, enable disable....







    Devices used during testing: XBox360W controller, ThrustMaster Wheel FFD, Wiimote + Nunchuk.

    One classic Gamepad controller, one Wheel and complex controller.



    6) Handling input axis and buttons as digital or analog

    Second abstraction is that you can use digital or analog output no matter your real input source is, meaning for ex. Joystick Axis is analog source giving input from 0.0 to 1.0, but can be tracked as digital true/false, or mouse button which is digital would return float values 0.0 to 1.0 while hold .


    Code (CSharp):
    1. //DIGITAL
    2.     if (InputManager.GetInputDown((int)States.Wave,Player,true))
    3.         {
    4.             animator.Play((int)States.Wave);
    5.         }
    6.  
    7.         if (InputManager.GetInputDown((int)States.Jump))
    8.         {
    9.             animator.Play((int)States.Jump);
    10.         }
    11.  
    12.  
    13.         //ANALOG
    14.         //
    15.         float forward = Math.Abs(InputManager.GetInput((int)States.WalkForward,Player, 0.25f))
    16.             - Math.Abs(InputManager.GetInput((int)States.WalkBackward,Player, 0.25f));
    17.  
    18.  
    19.  
    20.         animator.SetFloat(forwardHash, forward);
    21.         //
    22.         //
    23.         float turn = Math.Abs(InputManager.GetInput((int)States.TurnRight,Player, 0.25f))
    24.             - Math.Abs(InputManager.GetInput((int)States.TurnLeft,Player, 0.25f));
    25.  
    26.         animator.SetFloat(turnHash, turn);




    7) Create combination of inputs that would trigger action/state

    So you not need to open that nasty InputManager Tree component. Connect your test controller to your computer. Open InputMapper Editor in Window->Editor .

    Map inputs to state by just clicking keys/mouse/buttons or moving joystick as SINGLE, DOUBLE and LONG and make combination of inputs(Combos). Primary and secondary. In bellow example I've map to Wave state combo of Mouse0 double clicks + Joystick1AxisYNegative (Long pull backward of the Joystick) + double click of letter Y.







    You can set modifier format or clicks sensitivity.









    Select Player and then profile to start mapping states to inputs. When controller is attached, its profile would appear in profile list under "default". You can use "Clone default" to clone states from default to controller specific settings. Then you can change mappings. You can also clone Player to other players and add difference changes.




    8) Handling inputs by events

    As Update method get overcrowded, library offer modern input handling solution by use of Event based system.




    Code (CSharp):
    1.   InputManager.addEventListener((int)States.Wave).UP += onUp;
    2.         InputManager.addEventListener((int)States.Wave).DOWN += onDown;
    3.  
    4.  
    5.     void onUp(object o, EventArgs args)
    6.     {
    7.         Debug.Log("Up");
    8.     }
    9.  
    10.     void onDown(object o, EventArgs args)
    11.     {
    12.         Debug.Log("Down");
    13.     }
    or use editor:






    Hardcode developers can manually map input to states and even mix with loaded settings. This is useful mainly for testing.






    Code (CSharp):
    1. InputManager.loadSettings(Path.Combine(Application.streamingAssetsPath,"InputSettings.xml"));
    2.  
    3.  
    4.       InputManager.MapStateToInput ("WalkForward", InputCode.W.SINGLE);
    5.       InputManager.MapStateToInput ("WalkForward", 1, Mouse1.SINGLE);//Secondary
    6.     //InputManager.MapStateToInput ("WalkForward", InputCode.JoystickAxisPositive.SINGLE);
    7.  
    8.  
    9.       InputManager.MapStateToInput ("WalkBackward", InputCode.S.SINGLE);
    10.       InputManager.MapStateToInput ("WalkBackward", 1, InputCode.Mouse0.SINGLE);//Secondary
    11.     //InputManager.MapStateToInput ("WalkBackward", InputCode.JoystickAxisNegative.SINGLE);
    12.  
    13.    //map full axis (useful for analog input)
    14.    InputManager.MapStateToInput ("ManualFullAxisMap", InputCode.Joystick0AxisX);
    15.  
    16.    //adding input-states pairs manually
    17.    InputManager.MapStateToInput("Click_W_x2_C_State", Input.W.DOUBLE,InputCode.C.SINGLE);
    18.  
    19.  
    20.    InputManager.MapStateToInput("My State1",new InputCombination("Mouse1+Joystick12AxisXPositive(x2)+B"));

    In InputCode all KeyCode stuff are supported plus additional for Joystick Axis mapping.











    9) Plug and play instead of plug and pray.









    10) Profiles:

    Create profiles(layouts) for your device by just click button or move axis of connected device.







    Profiles are stored in DeviceProfiles.asset.











    User Interface:

    Drag and drop InputComponent to empty GameObject.























    User can choose what controller will assign to which player.

    When user attach controller, its layout with predefined settings would be loaded . Instead seeing "Joystick4Button10" you will see "Y","A","B"....
















    GITHUB: https://github.com/winalex/Unity3d-InputMapper



    Code is free if you contribute by solving bug or enhance something !!! Joking :) Who can stop you/us.



    Feedback, Forks are welcome if you aren't too smart, too movie star or too busy making money.

    Gmail me as winxalex.



    Knowledge should be free.



    19.08.14 Thrustmaster wheel RGT FFD demo WIN+DROID









    13.07.2014 Added WiimoteDevice and WiimoteDriver Skeleton

    22.07.2014 Quite more stability and plug in/out supported added.

    26.07.2014 Web Player joystick support (Chrome, FireFox)











    01.10.2014 WiiDevice and WiiDriver

    05.10.2014 XInput driver pure C# (No DirectX xinput.dll wrappers)

    13.10.2014 (OSXDriver default driver pure C#)

    17.10.2014 (Thrustmaster Wheel FFD and XBOX360W working on OSX)

    CONCEPT PROVED!!!


    18.10.14 Added much simplified sample scenes then previous hard core sample



    Plans: 1)Make some kind of pluggin structure so you put ur .dll driver in same folder and get reflected in runtime

    2) Adding accept time between 2 inputs



    24.12.2014 HappyHolidays. In past 2 weeks I was working day/night to cure child diseases of InputMapper. Tons of bugs were smacked, many sections are heavily tested, optimized, synced or redone and new features like mapping axis as whole or as from any device easily were introduced.



    10.01.2015 v1.2 Announced. Profiles, multiplayer and big redesign of the system.



    Issues:

    InputMapper might crash Unity Win????

    Generation of "States.cs" doesn't work in OSX???
     

    Attached Files:

    Last edited: Jan 25, 2015
  2. winxalex

    winxalex

    Joined:
    Jun 29, 2014
    Posts:
    166
  3. YaserDev

    YaserDev

    Joined:
    Aug 17, 2016
    Posts:
    20
    Very nice.
    It looks like exposing the input manager settings feature hasn't been implemented in unity yet.
     
    Deeeds likes this.