Sign in to follow this  
cozzie

Input handling and mapping

Recommended Posts

Hi all,

While working my way through Game Engine Architecture (the book), I've arrived at the point of creating/ improving my main loop and input handling. Besides these chapters I've the read the 'known' article on input handling by Apoch.

Concluding from this, I've decided to go for the following approach:

Main loop:

  1. For each iteration: get low-level input from HID's.
    Register events.
  2. Fixed update time for physics/logics (i.e. 60fps).
    Process events (once)
  3. Render as quick as technically possible (vsync or not, doesn't matter)

Input handling layers:

A. HID input is stored (step 1), low level; keys up/down, button states etc.

B. Mapping HID input with game actions, i.e. VK_UP = move forward

C. Process game action events in step 2 (i.e. move forward)

Data/mappings:

  • List of game actions
  • mapping each HID input with a game action.
    Providing flexibility for supporting multiple HID's and changing bindings
  • Mapping will include a game state, to have different actions with the same input, depending on game state

Registering events, struct/ set of data per event:

  • Enum game_action
  • Timestamp
  • Processed Y/N

Things to think about:

  • How about handling history? key pressed longer, key combo's etc
  • Button/key down or pressed, how to distinguish?
  • Do I need a third layer, or will this suffice, a practical example
    Layer 1: keyboard input key V -> VK_UP
    Layer 2: VK_UP is 'bind' to the game action 'Move forward', with game state 'ingame'

    In the processing of events, the state is 'in game', then I'll simply loop through the events which are not yet processed.
    Process event, if the state of the game action matches the current game state. Set processed to 'true'.

My question; do you have any advice or warnings for this approach? Maybe things that can be done different/ better.
Any input is appreciated.

Edited by cozzie

Share this post


Link to post
Share on other sites

Usually I like to have a wrapper around the basic event handling which generates extra events if necessary (e.g. key-held event when key-down was more than X milliseconds ago and there's been no key-up yet, or double-clicks if 2 key-downs happen within a certain timespan) and stores state (e.g. returns IsPressed when key-down was more recent than key-up for that given key).

The input events shouldn't usually include the game action, because the input system should be game-agnostic. Ideally it is the game which receives the low level input events and maps them into game-relevant events. If you really want to do this in your input library, perhaps because you don't want to write a game-specific wrapper, use arbitrary numeric IDs or hashes, provided by the game.

I like to have a hierarchy of input handlers, each getting a shot at handling an event before handing it down - e.g. UI, then GameState, then Game, then Engine. Each one might have its own bindings/translation system translating hardware events or axes into in-game controls.

Some systems like to try and create a generic set of virtual keys so that bindings are platform independent (e.g. map XBox 'X' and PS4 'â–¡' as PRIMARY_BUTTON) , but this gets controversial when platforms might disagree on what the standard 'back' button should be, for example. Given that you can't abstract the platform away entirely (e.g. because you need to show buttons or keys onscreen for tutorials, input binding screens, etc), I'd argue that it's probably not worth bothering.

Combos are arguably game-specific and I'd probably just queue or buffer them in the game depending on that game's requirements. Your input events should include timestamps to facilitate this.

Share this post


Link to post
Share on other sites

I agree that it's very useful to generate 'helper' events, such as key-held and double-click, in a unified, platform-agnostic way. Some additional things to keep in mind, based on my experience implementing input systems using this design:

Modifier keys. Do you support them? Can they be bound independently (i.e. as non-modifiers)? Can more than one modifier be bound to a single key? How do you handle "conflicts" if one is bound as both a non-modifier and as a modifier to another key? What happens when the modifier key is released before the modified key (in terms of generating the 'up' event)? How far do you want to go to support them and their related issues?

Layered/hierarchical input contexts. How do you determine priority (statically, dynamically, is it designer-configurable, etc.)? How do you handle "pass-through" if a key isn't handled (or do you support this even if a key *is* handled)? What if a key is pressed while a context is active, but the context is deactivated before the key is released?

There's no right or wrong answer to any of these as it depends heavily on what your input system needs to support, but these are just some issues that you don't read about often but will definitely run into, and they have a big impact on your design and implementation. Modifier keys can be especially tricky if you don't settle on how you want to handle them upfront (of if you've worked with lead designers who absolutely must have every action bindable to every/any key).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this