Input System (InputActions) - UltraStar-Deluxe/Play GitHub Wiki

Input System

UltraStar Play uses Unity's new Input System to receive and respond to user input.

  • The input system allows static access to input device state
    • Example: Keyboard.current.leftCtrlKey.wasPressedThisFrame or Touch.activeTouches.Count
  • It also allows to model so called InputActions that can be bound to several triggers
    • Example: Open Context Menu can be triggered by Right Mouse Button, or Long press of touch or mouse, or Ctrl+Shift+F7

Advantage of the InputActions is that it separates the action from the input device and input handling.

InputActions Asset

The InputActions of UltraStarPlay are defined in Assets/Common/Input/UltraStarPlayInputActions.inputactions. The format of this file is JSON.

Unity has an integrated editor to edit InputActions (double click the UltraStarPlayInputActions file).

Constants for InputActions

InputActions can be referenced by a path, e.g. "songEditor/copy". To avoid typos and make refactoring easier, a constant is created for every InputAction in the R-class.

Thus, in code you should prefer the constant R.InputActions.songEditor_copy instead of the raw string. This ensures that the action exist.

These constants are updated via the menu item Generate > Create all C# constants

Note that a similar approach is used for translations (R.String), and theme color (R.Color).

InputManager

The InputManager provides static access to InputActions. Thereby, the InputActions are wrapped to reuse the API of UniRx Observables.

Example:

InputManager.GetInputAction(R.InputActions.usplay_back).PerformedAsObservable()
    .Subscribe(_ => highscoreSceneController.FinishScene());

Such bindings are typically placed in a class named ...SceneInputControl.

Solving Conflicts

Mostly two different kinds of conflicts occur when using InputActions.

  • Conflict 1: The same action is bound to do different things
    • Example: Escape is used to close a dialog and also to exit the current scene.
    • Solution: Bind the close-action of the dialog with higher priority and cancel further propagation of this event.
InputManager.GetInputAction(R.InputActions.usplay_back).PerformedAsObservable().Subscribe(_ => ExitScene());
InputManager.GetInputAction(R.InputActions.usplay_back).PerformedAsObservable(10 /* This is the priority */).Subscribe(_ =>
{
    CloseDialog();
    InputManager.GetInputAction(R.InputActions.usplay_back).CancelNotifyForThisFrame();
});
  • Conflict 2: One action is a part of another action
    • Example: Ctrl+Shift+F vs Ctrl+F
    • Solution: When listening for Ctrl+F, make sure that InputAction of Ctrl+Shift+F is not triggered as well
InputManager.GetInputAction(R.InputActions.stuffWithCtrlShiftF).PerformedAsObservable()
    .Subscribe(_ => DoStuffA());
InputManager.GetInputAction(R.InputActions.stuffWithCtrlF).PerformedAsObservable()
    // Only react if other InputAction is not triggered as well
    .Where(InputManager.GetInputAction(R.InputActions.stuffWithCtrlShiftF).InputAction.ReadValue<float>() == 0)
    .Subscribe(_ => DoStuffB());

Show available InputActions to User

Users want to know what they can do and how to do it.

The class AvailableInputActionInfo can create a string to show available InputActions and their bindings (for example, the SongEditorScene uses this).

The InputManager has a static method to add such an info text for custom input handling implementations (e.g. when using Keyboard.current directly instead of a dedicated InputAction).

InputManager.AdditionalInputActionInfos.Add(new InputActionInfo("Skip To Next Lyrics", "Navigate Right"));
⚠️ **GitHub.com Fallback** ⚠️