LLearnCode
Academy/games/Simulation foundations

intermediate · 24 minute study

Actions outlive individual input devices

Supporting keyboard, touch and controllers becomes fragile when every mechanic knows device-specific buttons. More devices should add adapters, not duplicate gameplay rules.

Loading progressEvidence grows with practice
Useful preparation · 1 prerequisite

Use this as a map, not a lock. If these ideas are familiar, continue.

  • A game is state evolving through time — A movement rule that feels correct on your laptop can double its speed on a faster display. Separate elapsed time from the number of drawings before building more mechanics.

First, build a mental model

A device says what physically happened. An action says what the player intends. The simulation reads move, aim, interact and pause; it should not care whether an arrow key, thumbstick or touch control produced them.

  1. Separate continuous levels from edges. Holding move-right is a level sampled each update. Opening the pause menu is usually a press edge, so one held button does not toggle the menu every frame.
  2. Track independent sources. If two fingers or a key and pointer hold fire, releasing one source must not release the others. A set of source IDs represents this ownership more accurately than one shared boolean.
  3. Pointer capture can keep receiving a drag outside its original element. Clear ownership on pointerup, pointercancel and lostpointercapture. Blur, hidden-tab transitions and controller disconnection also need a release policy.
  4. Gamepad axes are analog values. Apply a documented dead zone, clamp the result, and inspect the standard mapping before assuming button indices. Normalize a two-axis movement vector when diagonal keyboard input must not move faster.
  5. Limit preventDefault to focused game controls. Menus, editable inputs and keyboard navigation still need their normal behavior. A controller connection alone should not seize input focus from a touch user.
Read the codejavascript · educational example
const fireSources = new Set();
const press = source => fireSources.add(source);
const release = source => fireSources.delete(source);
const readFire = () => fireSources.size > 0;

press("keyboard:Space");
press("pointer:7");
release("pointer:7");
console.log(readFire()); // true: Space still owns fire
release("keyboard:Space");
console.log(readFire()); // false
// A device adapter supplies source IDs. A blur handler clears the set.
  1. Acquire

    Space and pointer 7 create two independent holds. The action is active because at least one owner exists.

  2. Release one

    Pointer 7 ends. Removing its source leaves Space's ownership intact; the action remains active.

  3. Release all

    Space ends or the game loses focus. When no owners remain, the next input sample reports fire = false.

Production thinking

Take this beyond the example.

Test combinations: key plus touch, two pointers, drag outside the button, pointer cancellation, controller disconnect, menu focus and repeated resume. Provide remapping and visible control labels where practical. Input sanitization is part of playability; it is not a substitute for server-side validation of competitive results.

Sources and further reading

Your evidence

unseen is a local learning signal, not a credential or proof of production competence.

Explain the mental model, then explicitly acknowledge it. Opening a page is not evidence.

Supported retries can complete this lesson. Independent evidence and delayed review determine the skill stage.

Next lesson · Movement is a vector; collision is a query →