ai-behavior-trees-util…
Engine-neutral behavior tree and utility AI code for NPCs in any language: Blackboard, reactive composites, decorators and…
Engine-neutral input architecture with Godot InputMap code: named actions, stick deadzones, buffered presses and rebinding with conflict checks. Use for controller support or a rebind menu, or a drifting stick, WASD on AZERTY, or a dropped press. Not for coyote time
Claude Code
$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill input-systems --agent claude-code
Codex
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill input-systems -a codex -y
Cursor
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill input-systems -a cursor -y
Gemini CLI
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill input-systems -a gemini-cli -y
GitHub Copilot
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill input-systems -a github-copilot -y
OpenCode
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill input-systems -a opencode -y
Windsurf
$ npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill input-systems -a windsurf -y
name: input-systems description: > Engine-neutral input architecture with Godot InputMap code: named actions, stick deadzones, buffered presses and rebinding with conflict checks. Use for controller support or a rebind menu, or a drifting stick, WASD on AZERTY, or a dropped press. Not for coyote time (`platformer`) or Unity and Unreal input assets (`unity-input-system`, `unreal-enhanced-input`).
Gameplay reads named **actions** (`jump`, `attack`, `move`); bindings from keys, buttons and touch to those actions are data. Rebinding, multi-device support and most input accessibility fall out of that one indirection. This skill is the engine-neutral architecture with Godot 4.7 code. For the engine's own input assets use `unity-input-system` or `unreal-enhanced-input`; Godot's `InputMap` is covered here.
**Not this skill:** coyote time, jump buffering and variable jump height belong to `platformer`, which owns the jump controller. Hit-stop and other juice that interact with buffers are `game-feel`. Writing the bindings file is `save-systems`. Menu focus and navigation rules are `game-ui-ux`.
1. **Inventory before editing.** List the existing actions (Godot: the `[input]` section of `project.godot`; Unity: the `.inputactions` file; Unreal: `IA_`/`IMC_` assets) and grep gameplay code for raw key reads (`is_key_pressed`, `KEY_`, `Input.GetKey`). Raw reads are the first thing to replace. 2. **Name actions by intent**, not by key, and give each one a keyboard and a gamepad binding. Touch routes through the same actions. 3. **Match the read to the action.** Edge (pressed this frame or tick) for discrete actions, held or axis for continuous ones. 4. **Filter analog input** with a radial deadzone and a separate response curve. 5. **Buffer discrete presses** that arrive a little before they are legal, measured in game time and consumed when they fire. 6. **Rebinding:** capture the next input, bind the physical key, reject or swap conflicts, save, and offer reset to defaults. Keep a way back to the pause menu that cannot be unbound. 7. **Check it yourself, then ask for the device test** (see "Check it" below).
if Input.is_action_just_pressed("jump"): # edge: true on the press frame or tick only
try_jump()
var dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
# get_vector applies a radial deadzone, rescales past it and caps length at 1,
# so diagonals are not faster. Use get_axis for a single axis.
# WRONG: Input.is_key_pressed(KEY_SPACE): unrebindable, keyboard-only, and a held
# check, so jump re-fires every frame.Engine equivalents: Unity Input System `InputAction` and action maps; Unreal Enhanced Input Actions plus Mapping Contexts.
# Raw sticks never rest at exactly zero. Apply a RADIAL deadzone (on the vector
# length), not per-axis, so diagonals aren't clipped into the axes.
func apply_deadzone(stick: Vector2, dead := 0.2, curve := 1.0) -> Vector2:
# dead == 1 cannot be rescaled; report invalid settings before stopping movement.
if not (dead >= 0.0 and dead < 1.0 and curve > 0.0):
push_error("apply_deadzone requires 0 <= dead < 1 and curve > 0.")
return Vector2.ZERO
var mag := stick.length()
if mag <= dead:
return Vector2.ZERO # inside deadzone -> no movement
# Rescale so motion ramps from 0 at the edge of the deadzone, not from `dead`.
var scaled := minf((mag - dead) / (1.0 - dead), 1.0) # some pads report > 1 on diagonals
return stick / mag * pow(scaled, curve) # curve > 1 = finer aim near center
# WRONG: clamping each axis separately — it carves a square hole and snaps to axes.Keep the response curve (exponent) separate from sensitivity (a gain on the result, usually a camera turn rate) and expose both in settings. Invalid settings report an error and return zero movement. Godot's `get_vector` already does this deadzone and rescale, using the average of the four actions' deadzones (0.2 per action by default) unless you pass one.
# action_buffer.gd: remember discrete presses briefly so an early press still fires.
extends RefCounted
var window := 0.15 # seconds; 0.1-0.2 suits attacks and dodges
var _pressed_at := {} # action -> game time of its latest press
func press(action: StringName, now: float) -> void:
_pressed_at[action] = now
func consume(action: StringName, now: float) -> bool:
if not _pressed_at.has(action) or now - _pressed_at[action] > window:
return false
_pressed_at.erase(action) # one press fires one action
return true
func clear() -> void: # on death, pause, cutscene, scene change
_pressed_at.clear()Feed it from the input read (`if Input.is_action_just_pressed("attack"): buffer.press(&"attack", clock)`) and call `consume` where the action becomes legal, such as the first frame after attack recovery. `clock` is game time you advance in `_physics_process`, so the window freezes during pause and hit-stop. When two buffered actions become legal on the same tick, choose by a fixed priority, not by dictionary order. Jump buffering and coyote time use the same idea but belong to `platformer`.
# Godot 4.7. Capture the next physical i
<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.
Engine-neutral behavior tree and utility AI code for NPCs in any language: Blackboard, reactive composites, decorators and…
Engine-neutral game audio technique: bus layout, volume sliders in decibels, loudness, ducking music under dialogue, adaptive…
Builds and tunes game cameras, engine-neutral with Godot and Cinemachine 3 mappings: 2D follow with deadzone and look-ahead,…
Plans, generates or sources, and validates consistent game art: style guides, sprites, pixel art, tilesets, icons and textures,…
Builds engine-neutral branching dialogue with Ink, Yarn Spinner or a small JSON graph runner: lines, choices, conditions,…
Designs engine-neutral enemy and NPC AI: picks FSM, behavior tree, utility or GOAP, and builds perception, steering and A*…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.