Input Subsystem =============== The Input Subsystem lets you dynamically map actions to inputs and query these inputs either directly or store their states in a plain structure which makes it easy for you to write unit tests or to record/simulate input in a game. Mapping Inputs to Actions ------------------------- Unity already lets you map inputs (keys or joystick axes and buttons) to actions. This makes it much easier to work with varying key bindings: bool isFirePressed = Input.GetButton("Fire1"); float movementSpeed = Input.GetAxis("Vertical"); This code does not have to care about which keys or axes are assigned to "Fire1" and "Vertical," nor does it have to do anything when those key bindings change. The only drawback of Unity's Input class is that you cannot change the key bindings from your scripts. Thus, you have to show the ugly Unity settings dialog if you want to let the player change any of the key bindings. With the InputMapper, you get the same functionality as provided by Unity's Input class, but you can reconfigure your key bindings at any time (and load or save them, too). // Somewhere in your setup code IAction fireAction = inputMapper.CreateAction("Fire1"); fireAction.BoundKeys.Add(KeyCode.C); // Somewhere in your per-frame updating code if(inputMapper["Fire1"].IsActive) { fireBullet(); } You can create as many actions as your game needs to and you can bind any number of keys or joystick axes to an action. +---------------------------------------------------------------+ | InputMapper | +---------------------------------------------------------------+ | + Actions : ICollection | | + CreateAction(name : string) : IAction | | + CreateAction(name : string, description : string) : IAction | | + UpdateIfNeeded() | +---------------------------------------------------------------+ | V +-------------------------------------------------+ | IAction | +-------------------------------------------------+ | + Name : string | | + Description : string | | + BoundKeys : ICollection | | + BoundJoystickAxes : ICollection | | + RemoveAllBindings() | | + IsActive : bool | | + WasTriggered : bool | | + State : float | +-------------------------------------------------+ Input Action Usage ------------------ Actions provide you with quite a few useful properties. You can change the input devices and buttons/axes they map to simply by modifying their `BoundKeys` and `BoundJoystickAxes` collections: IAction jumpAction = inputMapper.Actions["jump"]; // Remove all key bindings, then add the space key as the only binding jumpAction.BoundKeys.Clear(); jumpAction.BoundKeys.Add(KeyCode.Space); // Remove all joystick bindings, then add vertical axis up as the only joystick binding jumpAction.BoundJoystickAxes.Clear(); jumpAction.BoundJoystickAxes.Add(new JoystickAxis("vertical", false)); Most likely, you will do this when the user changes the key bindings in your game's options menu or when your game starts up and loads its configuration file. When the game runs, you can store your actions to avoid the costly string lookup on weak mobile CPUs or if you absolutely want to maximum speed possible: class MyPlayerController : MonoBehaviour { public void Inject(InputMapper inputMapper) { this.horizontalMovementAction = inputMapper.Actions["horizontal"]; this.jumpAction = inputMapper.Actions["jump"]; } public void FixedUpdate() { Move(this.horizontalMovementAction.State); if(this.jumpAction.WasTriggered) { Jump(); } } private IAction horizontalMovementAction; private IAction jumpAction; } Which brings us to the most important part of input actions: querying their current values. For this, there are three properties you can check: - IAction.Active Becomes `true` when at least one of the buttons associated with the action is being held down. Joystick axes bound to the action will cause `IsActive` to become `true` when they are moved to more than 2/3rds of their range, until they go below 1/3rd or their range. This prevents something called /hysteresis/ at the trigger point (meaning that the action would flicker between `true` and `false` because the joystick's analogue/digital conversion has some noise in it - imagine moving a cursor a dozen times when the user just meant to move it by one item). - IAction.State The analogue state of the action. Always stays within a range of 0.0 to 1.0. Buttons bound to the action will cause this to go directly to 1.0 when they're pressed. (Unity has an additional feature that lets the value grow slowly, but that feature is not provided by this library). Joystick axes, of course, map their analogous value directly. If multiple joystick axes are bound to an Action, the highest value returned by any of them counts. - IAction.WasTriggered This is a special property that tells you whether the action's `Active` property has become `true` at any time in the past. The value is reset to `false` at the end of the frame in which you checked it. Which means that checking it from multiple places in the same frame is not an issue (`WasTriggered` will be `true` for all checks during the same frame). Input States ------------ While you can directly use the InputMapper or work with IActions in your input handling code, this would be rather inconvenient since you'd have either carry a lot of references around (if you store the IActions created in the InputMapper) or risk mistyping the action names unless you create a bunch of constants somewhere. Another problem is that unless you remember to set up some default bindings in each scene you create, when you click the play button in Unity, there would be no inputs assigned, leaving you locked out from the game. All this is taken care of by the InputManager. The InputManager takes a plain class with public fields like this one: public class MyInputState { public MyInputState() { this.Jump = new Trigger(); this.Fire = new Trigger(); } public Trigger Jump; public Trigger Fire; } ...and stores the actual inputs in it so that you can use it as a convenient, all-in-one input state to work with in your input handling code: // Query the current state of the game's inputs MyInputState state = inputManager.GetState(); if(state.Fire.IsActive) { fireBullet(); } To specify the default bindings that should be used if no other bindings are provided, you can add a simple attribute to each field: public class MyInputState { public MyInputState() { this.Jump = new Trigger(); this.Fire = new Trigger(); } [ DefaultKey(KeyCode.Space), DefaultKey(KeyCode.Joystick1Button1), ] public Trigger Jump; [ DefaultKey(KeyCode.LeftControl), DefaultKey(KeyCode.Joystick1Button0), ] public Trigger Fire; } Now, when you press the "Play" button in a Unity scene, skipping your main menu and key binding assignment, you can rely on the default bindings. In short, all your input handling code has to do now is this simple call: MyInputState state = inputManager.GetState(); ...and you will use the default mappings (eg. if you run a scene in the editor where your game's menu doesn't get to load the saved key configuration). If, instead, the scene is entered normally after your game loaded its key configuration (the 'Jump' and 'Fire' actions already exist), then the `DefaultKey` and `DefaultJoystickAxis` attributes will be ignored.