今日速览

  • 手柄不是「加分项」而是「及格线」:Steam 上有大量玩家在客厅/Steam Deck 上用手柄玩,一款不支持手柄的游戏会直接丢掉这部分用户,还会拖累 Steam Deck 兼容性评分。
  • Godot 的正确姿势是 InputMap:所有输入都定义成 action(move_left、jump…),键盘和手柄都映射到同一个 action;代码里永远只读 action,绝不出现 KEY_A 这种硬编码按键。
  • 摇杆一定要用 Input.get_vector():它自带圆形死区;如果用两个 is_action_pressed() 自己拼方向,会变成方形死区,斜向移动会莫名变快。
  • Steam Input 官方定义的「完整支持」四件事:① 用正确的手柄图标(glyph)提示按键 ② 配置器里显示游戏内动作而不是 K/L 键 ③ 发布官方手柄配置 ④ 不限制玩家自定义输入(键鼠/手柄可混用)。
  • 手感细节别漏:震动(Input.start_joy_vibration())必须给开关/强度滑条;1080p 下 UI 字体 ≥24px;Big Picture 下默认全屏(检测 SteamTenfoot 环境变量)。

核心学习内容

1. 一套代码同时吃键鼠和手柄:InputMap + action

在 项目设置 → 输入映射(Input Map) 里建 action,每个 action 可以挂多个事件:move_left 同时绑「键盘 A / 左方向键 / 手柄左摇杆轴」。这样代码只有一条逻辑路径,无需为手柄写第二套代码。

取值方式要选对:

需求方法
双轴移动(摇杆/WASD)Input.get_vector() — 圆形死区
单轴双向(油门/方向)Input.get_axis()
模拟量强度 0~1Input.get_action_strength()
布尔(按钮/跳跃)Input.is_action_pressed() / is_action_just_pressed()
extends CharacterBody2D

@export var speed := 220.0
@export var jump_velocity := -420.0
var gravity := ProjectSettings.get_setting("physics/2d/default_gravity")

func _physics_process(delta: float) -> void:
	# 键鼠和手柄走同一条路径,get_vector 自动处理圆形死区
	var dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
	velocity.x = dir.x * speed
	velocity.y += gravity * delta

	if is_on_floor() and Input.is_action_just_pressed("jump"):
		velocity.y = jump_velocity

	move_and_slide()

2. 自动识别「玩家现在用什么设备」并切换 UI 图标

玩家可能中途从手柄换回键鼠。做一个全局监听,输入事件一变就通知 UI 换图标(手柄显示 A / B,键鼠显示 Space / Esc):

# Autoload 单例:InputDevice.gd
extends Node

signal device_changed(is_gamepad: bool)
var is_gamepad := false

func _input(event: InputEvent) -> void:
	if event is InputEventJoypadButton or event is InputEventJoypadMotion:
		if not is_gamepad:
			is_gamepad = true
			device_changed.emit(true)
	elif event is InputEventKey or event is InputEventMouseButton:
		if is_gamepad:
			is_gamepad = false
			device_changed.emit(false)

小技巧:Godot 4.5 起在 Windows/macOS/Linux 上改用 SDL3 做手柄支持,兼容的手柄型号和主流引擎基本一致;但 Android/Web 仍是引擎自带实现,个别手柄可能表现不同,要多平台各测一遍。

3. 死区、震动与 Steam Input 的取舍

  • 死区(Deadzone):老手柄摇杆会「漂移」。可在 action 里调 deadzone,或直接给玩家一个「摇杆灵敏度」选项。get_vector() 的死区是圆形的,比手工拼接更符合直觉。
  • 震动(Haptic):Input.start_joy_vibration(device, weak, strong, duration) 起震,Input.stop_joy_vibration() 停震。必须提供关闭/降低震动的滑条——震感对部分玩家是干扰,也是无障碍刚需。
  • Steam Input:如果同时用 SDL,建议用 SDL 2.0.8+,Steam 才能让 SDL 忽略已被 Steam Input 接管的设备,避免「一次按键触发两下」的双输入 bug;用 ISteamInput::GetInputTypeForHandle 可判断具体手柄型号,用于做差异化辅助瞄准。

4. Steam Deck / 大屏「完整支持」清单

想在 Steam 上被认真对待,逐条对照:

  • ✅ 提示图标是对应手柄的 glyph,不是键盘按键名
  • ✅ Steam 配置器里显示的是游戏内动作,且发布了官方配置
  • ✅ 不锁死输入方式,键鼠+手柄可同时混用
  • ✅ 需要文字输入时,能自动唤起 Steam 文本输入 UI
  • ✅ 没有必须用鼠标点的启动器(最好干脆没有 launcher)
  • ✅ 1080p 下字体 ≥24px、Big Picture 启动默认全屏、首启动自动匹配分辨率

🎯 DeepSeek 提示词(可直接复制)

提示词 1:生成「键鼠 + 手柄双输入」的角色控制器

你是 Godot 4 GDScript 专家。请为我写一个 2D 平台跳跃角色控制器脚本(CharacterBody2D)。

要求:
1. 只通过 InputMap 的 action 读取输入(action 名:move_left/move_right/jump),代码中不得出现任何硬编码按键常量(如 KEY_A),以便键鼠和手柄共用一套逻辑。
2. 水平移动用 Input.get_vector 或 get_axis,保证圆形死区、斜向不超速。
3. 包含重力、地面检测、跳跃,并把「跳跃高度」「移动速度」暴露为 @export 变量。
4. 加入 Coyote Time(离开平台后约 0.1s 内仍可跳)和 Jump Buffer(落地前约 0.1s 按跳会在落地瞬间生效)。
5. 变量命名清晰,关键行加中文注释。

输出格式:先给完整 .gd 脚本,再用一个 markdown 表格说明每个 @export 参数的作用与推荐取值范围。
约束:Godot 4.x 语法,不使用已废弃 API。

提示词 2:生成输入设备自动检测 + 图标切换的全局管理器

你是 Godot 4 GDScript 专家。请写一个 Autoload 单例脚本 InputDevice.gd。

功能:
1. 监听所有输入事件,判断玩家最近一次使用的是手柄还是键鼠。
2. 提供 is_gamepad 状态和一个 device_changed(is_gamepad: bool) 信号。
3. 提供 get_action_hint(action_name) -> String,根据当前设备返回该动作的提示文本,例如手柄返回 "A"、键鼠返回 "Space"(用一个可在外部扩展的字典映射)。
4. 给出在 Project Settings 中把它注册为 Autoload 的步骤,以及一个 HUD 脚本示例:订阅 device_changed 信号来刷新界面提示。

输出格式:完整脚本 + 注册步骤 + HUD 示例,全部用代码块。
约束:Godot 4.x GDScript;不用轮询(_process)判断设备,必须基于事件。

提示词 3:手柄相关代码的 Debug / 审查

你是资深游戏程序员的代码审查员。下面是我在 Godot 4 里处理手柄输入的代码:<粘贴代码>

请按以下清单逐条排查并给出修改后的代码:
1. 是否存在硬编码按键而绕过 InputMap 的情况?
2. 摇杆是否用了正确的死区处理(get_vector 优先)?斜向移动会不会超速?
3. 是否缺少手柄震动,或缺少关闭震动的设置项?
4. 手柄热插拔(连接/断开)时是否会崩溃或状态残留?
5. 输入提示图标是否随设备切换?

输出格式:先列「问题 → 风险 → 修复建议」表格,再给完整修订版脚本。
约束:只针对 Godot 4.x;不确定的地方标注假设,不要编造不存在的 API。

学习心得

把「手柄支持」单独拿出来学,是因为它直接决定游戏能不能上 Steam 的台面。之前我一直默认「键鼠能玩就行」,但 Steam 的新品节、Steam Deck 验证、以及大量沙发玩家都在用手柄——不支持手柄等于主动放弃流量。好在 Godot 的 InputMap 机制让这件事没那么贵:只要从第一行代码起就坚持「只读 action、不读具体按键」,键鼠和手柄就是同一套逻辑,后面接 Steam Input 的 glyph 和官方配置只是收尾工作。对「用 DeepSeek 做一款 Steam 游戏」的目标来说,这类有明确规范、有标准清单的模块特别适合交给 AI:我把 Steam Input 的「完整支持」四条喂给 DeepSeek,它就能帮我生成检查清单和配套代码,我只需逐条验收。

明日关注

  • 在 Godot 里实测:给同一个 action 同时绑键盘与手柄按键,跑一遍 get_vector 的死区与斜向速度。
  • 给跳跃补上 Coyote Time / Jump Buffer,配合手柄震动做一次「手感回调」。
  • 对照 Steam Input「完整支持」清单,列出本项目目前还差哪几条,排进待办。

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