Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.
Rewlion edited this page May 15, 2024 · 3 revisions

Every toy renderer requires an input, right? To fly the map, to click on something.
Sooooo let’s build an input with drivers, router and data driven Steam Input api like with actionsets and support for double clicks, long click, after long click...
suuure why not

There are 3 Input layers to discuss:

  • OS specific input drivers
  • Input Router
  • Steam Input API like gameplay input system.

OS Specific input driver

it’s just a class that handles OS events, i.e. from win32 WindowProc.
There are two different drivers: keyboard and pointer.
Pointing device on windows is mouse handler, it’s possible to use it for touchpad on android for example.

Every input driver has it’s specific listener that got notification on device state change with transformed event information.
For gamepad it would be a separate gamepad driver.

Input Router

It is a middle point that accumulates all input drivers notifications and redirects it to the router listeners.
Each input router listener has it’s priority and after input processing it able
to consume the input thus nobody after will process the event.\

Examples of input router listeners: Editor , Gameplay Input, Game Reactive UI.

Right now Editor is just an ImGui Layer, when we activate debug console we would like to consume all the input events thus after pressing keyboard keys we do not fire any gameplay events.

Steam Input API

Copy paste from Steam concepts that is almost valid for the toy renderer:

  • Actions are the events that the Steam Input API uses to orchestrate everything.
    In native mode, your game doesn’t get a ”Button A pressed” event, it simply gets a ”Jump” event (or whatever), and what kind of input causes ”Jump” is entirely in the hands of the player.

  • Digital actions are the simplest and most common kind of action. They are simply on or off, so the game simply polls repeatedly and listens for the state of these actions.
    Analog actions have one or more axes of data and are used for things like smoothly moving characters, steering cars, controlling cameras, etc.
    Standard joystick- and mouse- driven actions will usually have two axes, X and Y, but single-axis analog actions are possible too (such as those commonly bound to analog triggers);
    In this case the action data will still report two axes, but the Y axis will always be zero.

  • Action Sets is a logical grouping of associated actions.
    Only one action set can be active for any given input device at a given time.
    For instance, you can create a ”menu” action set that is only active during menu sequences, as well as ”driving”, ”walking”, and ”flying” action sets for a game like GTAV that features multiple vehicle and movement modes

Toy Renderer Input API

Instead of digital, analog actions there are button, joy move, joy delta, actions.

button action: digital action that has different modes:

  • pressed - true when button is pressed
  • on press - true once on active front of pressing
  • on release - true once on releasing fron of pressing
  • on double click - true once after double click
  • on long press - true once after long pressing
  • long pressed - true after long press time Long pressing time: 250ms

joy delta action: analog action that sets device axis position as is.
Active if position changed.

joy move action: analog action that sets delta of device axis position.
Active if delta is not zero.

Actions are globally unique and created lazily during ActionSet description,
thus if we have Button action Move in ActionSet Human it can not be changed to JoyMove in ActionSet Vehicle.

This input API is purely data driven.
There are two different files: actionsets descriptions and actions bindings.

ActionSets description and Binding files (order is important):

//some action_sets.ed
ActionSets
{
  Human
  {
    MoveLeft @("button")
    {
      mode:t ="on_release"
    }
    CameraRotation @("joy_delta")
    {}
  }
  
  RespawnSelection
  {
    RespawnPlaceMovement @("joy_move")
    {}
  }
}
//some bindings.ed
Bindings
{
  MoveLeft
  {
    device:i = 0
    button:i= 34
  }
  
  CameraRotation
  {
    device:i = 1
    x_axis:i = 0
    y_axis:i = 1
  }

  RespawnPlaceMovement
  {
    device:i = 1
    x_axis:i = 0
    y_axis:i = 1
  }
}

C++ usage

//somewhere in setup logic
Input::Manager::enableActionSet("Human", true);
...
//processing actions
int moveLeftId = Input::Manager::getButtonActionId("MoveLeft");
bool isMovingLeft = Input::Manager::getButtonActionState(moveLeftId);

int rotationId = Input::Manager::getAnalogActionId("CameraRotation");
float2 delta = Input::Manager::getAnalogActionData(rotationId);
Clone this wiki locally