今日速览

  • 代码里永远不要出现 Key.KEY_SPACE 或 JOY_BUTTON_A,只写 action 名("jump")。硬编码按键 = 以后想支持手柄就要全项目重构。
  • 移动用 Input.get_vector() 而不是自己拼 x/y,它自带归一化,否则斜向走位会快 41%。
  • 手柄摇杆必须设死区(deadzone),Godot 默认 0.5 太钝,实战取 0.2~0.25,并区分「移动死区」和「瞄准死区」。
  • 一次性动作走 _unhandled_input,持续性输入走 _physics_process——混着写就会出现「按一次跳两下」。
  • Steam Deck Verified 的输入检查项很硬:默认配置必须能玩通全部内容、图标必须和实际按键一致、不能让玩家先去设置里开手柄。

核心学习内容

1. InputMap:把「按键」和「意图」切开

Godot 的输入系统核心不是 InputEvent,而是 InputMap:你在 项目设置 > 输入映射 里定义一堆 action(move_left、jump、interact、pause),每个 action 挂多个 InputEvent——键盘的 W、手柄的左摇杆左推、甚至鼠标侧键,全都绑在同一个 action 上。

代码只认 action:

func _physics_process(delta: float) -> void:
    var dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
    velocity = dir * speed
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = jump_force
    move_and_slide()

这一层的价值在于:换平台不改代码。Steam Deck 的摇杆、Xbox 手柄的 A 键、键盘的空格,对游戏逻辑来说都是「jump」。Steam 的控制器配置(Steam Input)甚至能在不改你二进制的前提下把 Deck 的触控板映射成键鼠——前提是你的游戏能纯键盘/纯手柄玩通。

2. 事件 vs 轮询:两套 API 别混用

  • 事件式(_input / _unhandled_input):一次性触发。跳跃、开菜单、交互。用 _unhandled_input 而不是 _input,这样 UI 按钮先吃掉点击,不会「点按钮的同时角色也开了一枪」。
  • 轮询式(_physics_process + Input.is_action_pressed / get_vector):持续性输入。移动、持续射击、蓄力。

最常见的 bug 是把 is_action_just_pressed 写在 _process 里——帧率不稳定时手感和判定都会飘;移动逻辑一律放 _physics_process,和物理帧对齐。

3. 死区与「手感翻译」

摇杆静止时也会输出 0.02~0.08 的噪声。Godot 的 InputEventJoypadMotion 有 axis_value 和 InputMap 里的 deadzone 属性:

# 运行时把 jump 的死区调紧一点,避免轻碰就触发
for ev in InputMap.action_get_events("move_left"):
    if ev is InputEventJoypadMotion:
        ev.deadzone = 0.25

更有用的是响应曲线:把摇杆的线性输入过一遍 pow(strength, 1.5),小推慢走、大推快跑,同样的 speed 值手感立刻「有重量」。这是 3 行代码换来的最大手感提升。

4. 图标切换 + Steam Deck Verified

PS 手柄显示 ✕○□△,Xbox 显示 ABXY,Steam Deck 又是另一套。做法很简单:监听 Input.joy_connection_changed 和每次输入事件的设备类型,存一个 last_device 枚举,UI 层读取它切换贴图。Steam Deck 的兼容性检查里明确要求「屏上图标必须和实际输入一致」,这条不做就是 Playable 而不是 Verified。

对照 Steamworks 的 Deck 兼容清单,和输入相关的硬指标有:

检查项你要做的事
手柄默认可用不改设置就能用手柄玩通全部内容
图标匹配显示当前设备的真实按键符号
文字输入需要打字的地方调用屏上键盘
可读性最小字号在 1280×800 上手机会看得清
无启动器别一进游戏先弹个第三方 launcher

Deck 是 1280×800、7 寸屏。你的 UI 在 4K 上调好的 10px 字,到 Deck 上等于看不清——这条比输入更容易翻车。

5. 运行时重映射(可选但加分)

InputMap.action_erase_events(name) + InputMap.action_add_event(name, event) 就能实现设置里的改键。把 event.as_text() 和 event.get_class() 序列化成 JSON 存进 user://controls.cfg,启动时读回来。注意重映射界面要拦住「同一个键绑了两个 action」的冲突。

🎯 DeepSeek 提示词

① 生成 InputMap 初始化 + 持久化重映射脚本

你是一位 Godot 4.x GDScript 专家。

任务:为一个 2D 动作游戏写 input_manager.gd(Autoload 单例),负责:
1. 在 _ready() 里检查 InputMap 是否包含这些 action:move_left/right/up/down、jump、attack、interact、pause。缺失则用代码创建,并绑定默认键鼠 + 手柄。
2. 键鼠绑定:WASD 移动、Space 跳跃、鼠标左键攻击、E 交互、Esc 暂停。
3. 手柄绑定:左摇杆移动(deadzone=0.25)、A 跳跃、X 攻击、Y 交互、Start 暂停。
4. 提供 rebind(action: StringName, event: InputEvent) -> bool:先检查冲突(同一 event 已绑到别的 action 就返回 false),再执行重绑定。
5. 提供 save_bindings() / load_bindings(),把每个 action 的事件序列化为 JSON 存到 user://controls.json,用 FileAccess,读不到文件时静默用默认值。

约束:
- 只用 Godot 4 API(不要 Godot 3 的 InputEventKey.scancode)。
- 每个函数写中文注释说明「为什么这么做」。
- 不要用 class_name,靠 Autoload 名称访问。
- 序列化时 InputEventKey 存 physical_keycode(不要 keycode),InputEventJoypadButton 存 button_index。

输出:单个完整的 .gd 文件代码块,不要解释性文字。

② 让 DeepSeek 生成「输入抽象层 + 图标自动切换」

你是 Godot 4 的 UI/输入系统工程师。

背景:我的 2D 游戏要同时支持键鼠、Xbox 手柄、PS 手柄、Steam Deck,UI 上的操作提示需要显示对应设备图标。

任务:写两个文件。
1. device_detector.gd(Autoload):监听输入事件和 Input.joy_connection_changed,推断当前设备类型,暴露枚举 Device { KEYBOARD, XBOX, PLAYSTATION, STEAMDECK, GENERIC_PAD } 和信号 device_changed(device)。判断依据:InputEventJoypadButton/JoypadMotion 时读取 Input.get_joy_name(device) 关键词("Xbox"/"DualSense"/"PS"/"Steam"),键盘事件则回落 KEYBOARD。
2. prompt_icon.gd(TextureRect 或 TextureButton 脚本):export 一个 action 名,运行时按 Device 从字典里取对应贴图路径并 set_texture,同时订阅 device_changed 自动刷新。

约束:
- 贴图路径规则:res://assets/ui/glyphs/{device}/{action}.png,缺失时回落到 {device}/generic.png 并在控制台 push_warning。
- 不要每帧轮询,只在事件发生时更新。
- 用 typed GDScript(参数和返回值都标类型)。
- 附一段 20 行以内的使用示例(在场景里怎么挂)。

输出:两个完整脚本 + 使用示例,各自独立代码块。

③ 让 DeepSeek 按 Steam Deck 清单审计你的输入/UI

你是 Steam Deck 兼容性审核员,熟悉 Steamworks 的 Deck Verified 检查清单。

输入:我会贴出我的项目结构、InputMap 配置(或相关脚本)和 UI 场景代码。

任务:按下面 6 项逐条判定「通过 / 不通过 / 无法判断」,不通过的要给出具体修改方案(改哪个文件、改哪几行、改成什么):
1. 不进入任何设置菜单,手柄能否玩通全部内容?
2. 所有需要文字输入的地方是否调用了 OS 屏上键盘(DisplayServer.virtual_keyboard_show)?
3. 屏上按键图标是否随当前设备切换,且与实际按键一致?
4. 在 1280×800 分辨率、7 寸屏下,最小字号是否 ≥ 16px 且高对比?
5. 游戏启动是否依赖第三方启动器或外部程序?
6. 暂停/退出/存档是否都能用纯手柄完成?

输出格式:Markdown 表格(检查项 | 判定 | 依据 | 修改方案),表格后列出「最可能卡住 Verified 的 2 个问题」并排序。
约束:不要泛泛而谈,每条修改方案必须能直接落地;无法从我给的材料判断的,明确写「无法判断,需要我提供 X」。

学习心得

输入系统是那种「做对了没人夸、做错了全是差评」的模块。今天最大的收获是把它当成一层抽象来看:游戏逻辑只认意图(action),设备差异全部挡在 InputMap 和 device_detector 后面。这样后面接 Steam Input、接 Deck 触控板、接自定义改键,都只是加映射表,不动一行业务代码。

对「用 DeepSeek 做一款 Steam 游戏」这个目标来说,这三条提示词的价值在于:输入层是规格明确、无需创意的部分——action 列表一列、约束一写,DeepSeek 一次就能吐出能跑的代码。真正要我自己想的是 action 怎么划分(哪些操作要合并、哪些要拆开),这才是设计决策。而第③条提示词把 Steam 的审核清单变成了可执行的 checklist,相当于发售前先自己审一遍——这种「把外部规则翻译成自检项」的用法,比让 AI 写代码更值钱。

明日关注

  • 把今天的 device_detector 接进暂停菜单,实测键鼠 ↔ 手柄热切换图标是否即时刷新
  • 查 Steam Input 的官方 action set / action layer 文档,看触控板能不能映射成虚拟摇杆
  • 用 OS.virtual_keyboard_show 给存档命名输入框加上 Deck 屏上键盘支持

本文由自动化学习流水线每日生成,坚持即学即记。