Saturday, July 26, 2014

Unity3d - InputMapper (Joystick in Web Player)

I really wanted to prove whole concept so I left this post underdeveloped. I'm proud to annouced that concept is proved not just web but Win,OSX and Droid.
 Main idea to use browser GamePad API (Still not supported by Safary and not W3C standard) came from that I couldn't find way how to solve the problem recognizing wheel turning  direction as Unity
static float GetAxisRaw(string axisName) return from full left to full right turn -1 to 1 to -1.  So I couldn't find what is left and write. I'm dumb and hate Unity Ultimate InputManager tree control so I decided to call GamePad API thru Mono behaviour and SendMessage




I succeed on both Chrome and FF despite their GamePad API aren't the same. 

 public void HaveGamepadEvents()
        {
            Application.ExternalEval(
            "if('GamepadEvent' in window) UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onHaveGamepadEvents','1');" +
            "else UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onHaveGamepadEvents','0');"  
           );
        }


First have events and second need pool loop in order to track connecting/disconnecting of devices
 if (hasGamepadEvents)
            {
                _hasEvents=true;
 Application.ExternalEval(
   //  "window.addEventListener('gamepadconnected',function(e){  var buttons = [];  for (var i = 0; i < e.gamepad.buttons.length; i++)   buttons[i] = e.gamepad.buttons[i].value; UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onDeviceConnectedEvent',JSON.stringify({ id: e.gamepad.id, axes: e.gamepad.axes, buttons: buttons, index: e.gamepad.index }))});" +
   //  "window.addEventListener('gamepaddisconnected',function(e){ UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onDeviceDisconnectedEvent',e.gamepad.index.toString())});"
      "window.addEventListener('gamepadconnected',function(e){   UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onDeviceConnectedEvent',JSON.stringify({ id: e.gamepad.id,  numButtons:e.gamepad.buttons.length, numAxes:e.gamepad.axes.length,  index: e.gamepad.index }))});" +
     "window.addEventListener('gamepaddisconnected',function(e){ UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onDeviceDisconnectedEvent',e.gamepad.id)});"
           
           );



            }
            else//manuall check
            {
               

                Timer enumeratorTimer = new Timer(1000);
                enumeratorTimer.Elapsed += new ElapsedEventHandler(EnumerateGamepadsTimedEventHandler);
                enumeratorTimer.Enabled = true;
            }




Manual Enumeration:
 
private string ENUMERATE_COMMAND = "var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);" +
                                              "for (var i = 0; i < gamepads.length; i++) {"+
                                              " var gamepad=gamepads[i]; " +
                                              
                                                "if (gamepad) {"+
                                                   
                                                  "UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onDeviceConnectedEvent',JSON.stringify({ id: gamepad.id, numButtons:gamepad.buttons.length, numAxes:gamepad.axes.length,  index: gamepad.index }));" +
                                               " }"+
                                              "}";



Reading position commands where defined like:
 
 private string GAMEPAD_COMMAND = "var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);" +
                                          "if(gamepads.length>0 && gamepads[{0}]){{" +
                                          "UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onRead',JSON.stringify(gamepads[{0}]));" +
                                          "}}else{{"+
                                          "UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onDeviceDisconnectedEvent','{0}');"+
                                          "}}";

        //FF JSON doesn't work well
        private string GAMEPAD_COMMAND_COMPLEX = "var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);" +
                                        "if(gamepads.length>0 && gamepads[{0}]){{" +
                                        "var gamepad=gamepads[{0}]; var buttons = [];  for (var i = 0; i < gamepad.buttons.length; i++)   buttons[i] = gamepad.buttons[i].value;"+
                                        "UnityObject2.instances[0].getUnity().SendMessage('WebHIDBehaviourGO','onRead',JSON.stringify({{ id: gamepad.id, axes: gamepad.axes, buttons: buttons, index: gamepad.index }}));" +
                                        "}}";
Read function
 

            public void Read(int index)
            {
               // UnityEngine.Debug.Log(String.Format(GAMEPAD_COMMAND, index));
                if(_hasEvents)
                    Application.ExternalEval(String.Format(GAMEPAD_COMMAND_COMPLEX, index));
                else
                    Application.ExternalEval(String.Format(GAMEPAD_COMMAND, index));
            }
I've very low opinion for JSON and dynamic object {} as increase data size and parsing time
and don't know why JS is forced overall but used it as quickest solution.  Even then JSON on FF failed to stringify Gamepad objects.


Demonstration shows controller input remapping while playmode (button  of Thrustmaster wheel and then on wheel positive X axis) to AnimationState Wave. 


No comments:

Post a Comment