关于 input-systems
input-systems 是面向游戏开发的引擎无关输入架构技能,适用于设计控制映射和无障碍操作。它以命名动作隔离设备输入,并涵盖模拟输入处理、缓冲和重新绑定。
主要功能
- 01以命名动作映射物理输入
- 02支持键盘、手柄和触控
- 03处理模拟输入死区与灵敏度
- 04输入缓冲与宽容跳跃窗口
- 05重新绑定及冲突检测
适用场景
- 01设计跨设备游戏控制
- 02为模拟摇杆设置死区
- 03实现可重新绑定的控制界面
- 04调校跳跃输入响应
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill input-systems安装后在 Claude Code 中输入/input-systems确认已加载。
附带文件references/buffering-and-accessibility.md
详细介绍
输入系统
切勿让游戏玩法直接依赖原始按键。将物理输入(按键、按钮、触摸)
映射到命名的 动作(jump、interact、move),并让游戏玩法读取动作。
仅这一层间接映射,就几乎能免费实现按键重映射、多设备支持和无障碍功能。
本技能介绍与引擎无关的架构;请将其绑定到
unity-input-system、unreal-enhanced-input 或 Godot 的 InputMap。
适用场景
- 用于设计输入层:动作、绑定、多设备,以及带冲突检测和绑定保存功能的 重映射 UI。
- 用于添加模拟输入处理(死区、灵敏度)和游戏手感功能 (输入缓冲、土狼时间)。
- 用于让操作更易于使用(完全重映射、按住与切换、灵敏度、 不要求同时按下多个按键)。
**不适用场景:**要使用特定引擎的具体输入包/API,请使用
unity-input-system、unreal-enhanced-input 或 Godot 的 InputMap。对于缓冲所服务的
移动/跳跃 物理机制,请参阅 physics-tuning 和引擎的移动技能。
将绑定持久化到磁盘请使用 save-systems。
核心工作流
- **定义动作,而非按键。**游戏玩法应询问“
jump是否按下?”,而不是“是否按下了 Space?”。动作是稳定的接口约定;绑定则是数据。 - **按设备绑定。**每个动作都可以绑定键盘、手柄和触摸输入。最后发送输入的设备就是 当前活动设备;切换 UI 提示以匹配设备。
- **读取正确的触发状态。**离散动作(跳跃、交互)使用 本帧刚按下(边沿), 连续动作(移动、瞄准)使用 按住(电平)。混淆两者会导致重复触发或漏掉按键。
- **过滤模拟输入。**为摇杆/扳机应用死区,让静止时的漂移被视为零,并按需调整 灵敏度/曲线。
- **通过缓冲改善手感。**短暂记住已按下的动作,让稍早按下的输入仍能触发 (输入缓冲);离开平台边缘后,也允许在短时间内跳跃(土狼时间)。
- **将重映射作为核心功能。**UI 应能捕获下一个输入、检测冲突并持久化绑定,
同时提供恢复默认设置的功能。使用
save-systems保存。 - 在每种设备上验证,并测试重映射:键盘、手柄、触摸;在游戏过程中重映射 一个动作,并确认游戏玩法和提示都会随之更新。
模式
1. 使用动作而非原始按键;区分边沿与按住
# Gameplay reads ACTIONS. The mapping from key/button to action lives in data.
# Discrete (edge): fire once on the press frame.
if Input.is_action_just_pressed("jump"):
try_jump()
# Continuous (held): read every frame as an axis.
var move := Input.get_axis("move_left", "move_right") # -1..1
player.velocity.x = move * RUN_SPEED
# RIGHT: name actions ("jump"); rebinding/devices just change the binding data.
# WRONG: `if Input.is_key_pressed(KEY_SPACE)` — unrebindable, keyboard-only,
# and `is_key_pressed` is a held check that would re-fire jump every frame.
引擎对应功能:Godot InputMap + Input.is_action_just_pressed;Unity
Input System 的 InputAction / action maps;Unreal Enhanced Input 的 Input Actions +
Input Mapping Contexts。
2. 模拟输入死区与灵敏度
# 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, sens := 1.0) -> Vector2:
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 := (mag - dead) / (1.0 - dead)
return stick.normalized() * pow(scaled, sens) # sens>1 = finer near center
# WRONG: clamping each axis separately — it carves a square hole and snaps to axes.
3. 输入缓冲 + 土狼时间(带来宽容、灵敏的手感)
# Buffer: a jump pressed slightly BEFORE landing still triggers on touchdown.
# Coyote: a jump pressed slightly AFTER walking off a ledge still works.
const BUFFER := 0.12 # seconds an early press stays "remembered"
const COYOTE := 0.10 # seconds after leaving ground you can still jump
var _buffer_timer := 0.0
var _coyote_timer := 0.0
func _physics_process(dt):
_buffer_timer -= dt
_coyote_timer = COYOTE if is_on_floor() else _coyote_timer - dt
if Input.is_action_just_pressed("jump"):
_buffer_timer = BUFFER # remember the press
if _buffer_timer > 0.0 and _coyote_timer > 0.0:
velocity.y = JUMP_VELOCITY
_buffer_timer = 0.0; _coyote_timer = 0.0 # consume both so it fires once
4. 带冲突检测的重映射
# Capture the next physical input, reject duplicates, then persist.
func rebind(action: String, event: InputEvent) -> bool:
for other in actions: # conflict check across actions
if other != action and binding_of(other) == event:
return false # already used -> let UI warn/swap
set_binding(action, event) # engine: erase old + add new event
save_bindings() # persist (see save-systems)
return true
# Always provide "reset to defaults", and never let the player unbind a key they
# need to reach the menu without an alternative.
常见问题
- 在游戏玩法中硬编码按键会阻止重映射、让手柄/触摸设备无法使用,并导致输入逻辑 分散。只读取命名动作。
- 混淆边沿与按住:跳跃使用按住检查会导致每帧重复触发;移动使用边沿检查则会丢失 持续按住的输入。根据动作选择匹配的检查方式。
- 按轴分别设置死区会削弱摇杆的斜向输入,并让移动方向卡在坐标轴上。 应根据向量模长使用径向死区。
- 没有输入缓冲/土狼时间会让紧凑的平台跳跃游戏显得不公平,即使物理机制正确—— 玩家会说“我明明按了跳跃”。应加入较短的缓冲窗口。
- 重映射时不处理冲突会让两个动作共用同一个按键,或因取消菜单操作绑定而困住玩家。 应检测冲突,并确保玩家始终有办法恢复。
- 设备切换时不更换提示会向手柄玩家显示“按 Space”。应跟踪最后使用的设备并切换 按键图标。
- 忽视无障碍需求:要求同时按下多个按键、不支持重映射、灵敏度固定、操作只能按住。 应提供重映射、切换与按住选项以及灵敏度设置。
- 在错误的循环中读取输入:在物理更新步骤中轮询按住状态,以保证移动一致; 捕获离散按键,避免它们在帧间被漏掉。
参考资料
references/buffering-and-accessibility.md— 缓冲/土狼时间调校、跳跃手感 (可变高度、跳跃顶点)、设备检测与提示切换、触控操作, 以及无障碍检查清单(重新映射、切换/按住、灵敏度、延迟)。
相关技能
unity-input-system、unreal-enhanced-input— 具体的引擎输入 API (Godot 使用InputMap和Input单例)。save-systems— 持久化自定义按键绑定和输入设置。physics-tuning— 缓冲/土狼时间窗口所作用的移动机制。platformer、fps-shooter— 手感取决于输入处理的游戏类型。
评论
支持 Markdown