【Godot】【入门】输入系统详解:InputMap 动作映射(键鼠/手柄一套代码通吃)

编程达人挑战赛·第6期 10w+人浏览 170人参与

解决“键位乱写、手柄不响应、移动端没输入”三个痛点,教你用 InputMap 定义动作,一处配置多端通用,并附常见排查清单与代码模板。
在这里插入图片描述

为什么要用 InputMap 而不是硬编码按键

  • 一套动作名对应多个设备,代码不再关心具体键位:Input.is_action_pressed("move_left")
  • 便于改键、手柄/键鼠共存、移动端虚拟按钮接入。
  • 动作可调节“按下/释放阈值”、可区分连续/一次性事件。

InputMap 核心概念

  • 动作 (Action):自定义字符串,如 move_leftjump
  • 事件 (InputEvent):键盘、鼠标、手柄、触摸等输入的具体信号,挂在动作下。
  • 查询 APIis_action_pressed(持续)、is_action_just_pressed(边沿)、get_axis(组合轴)。

5 分钟完成基础配置

  1. 打开 Project → Project Settings → Input Map。
  2. 在 Action 栏输入 move_leftmove_rightjumpattack,点击 Add。
  3. 选中 move_left,点击 Add Event,按键盘 A 或 左方向键;再点一次添加手柄左摇杆负 X(按摇杆)。
  4. move_right 同理添加 D/右键 + 摇杆正 X。
  5. jump 添加 Space + 手柄 South(如 X/A)。
  6. 点击 Save,动作即存入项目。

推荐默认动作表(可直接粘贴)

  • move_left / move_right / move_up / move_down
  • jump / dash / attack / interact
  • pause / ui_accept / ui_cancel (保留 UI 默认动作)

代码写法模板

var input_dir := Input.get_vector("move_left", "move_right", "move_up", "move_down")
velocity = input_dir * move_speed

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

if Input.is_action_just_pressed("pause"):
    get_tree().paused = !get_tree().paused
  • get_vector 自动归一化并考虑对角线速度;适合 2D 顶视角和 3D 平面。
  • 改键后代码无需变化,支持键鼠/手柄同写。

手柄支持要点

  • 摇杆事件是 InputEventJoypadMotion,添加时要推摇杆;
  • 按键是 InputEventJoypadButton,按下对应键即可录入;
  • 阈值:摇杆默认为 0.5,可在 Project Settings → Input Devices → Deadzone 调整。

鼠标常用事件

  • 左键:添加 Mouse Button → Left Button。
  • 右键/中键滚轮同理。
  • 鼠标移动用于相机:
func _input(event):
    if event is InputEventMouseMotion:
        rotate_y(-event.relative.x * mouse_sens)

触摸与虚拟按钮

  • 在移动端导出时,UI 按钮可在脚本中 button.pressed.connectInput.action_press("jump") 触发动作:
func _on_jump_button_pressed():
    Input.action_press("jump")
func _on_jump_button_released():
    Input.action_release("jump")
  • 这样代码仍然只看动作,不关心是触摸还是键盘。

动作强度与组合轴

  • Input.get_axis("move_left", "move_right") 返回 -1 到 1,自动考虑手柄轴强度。
  • 可自定义阈值:Input.get_action_strength("attack") 返回 0~1,适合模拟扳机。

事件优先级与冲突

  • Godot 按输入队列顺序处理,同一帧可能多次触发;如需阻断,使用 event.accept()
  • UI 捕获:Control 节点会优先处理 UI 输入。游戏内监听 _unhandled_input(event) 以避免被 UI 吃掉。

常见问题排查清单

  • 动作没触发:检查是否在运行时新建了场景但没保存 InputMap;尝试 Project → Reimport。
  • 手柄不起作用:确认驱动识别(Editor 顶部工具栏有手柄图标),摇杆 Deadzone 过高也会导致无响应。
  • 键位冲突:UI 与游戏共用 ui_accept 等默认动作时,按钮获得焦点会触发;解决方案:分离 UI 动作或在 _unhandled_input 处理中止。
  • 触摸延迟:移动端建议禁用鼠标仿真(Project Settings → Input Devices → Pointing → Emulate Mouse From Touch)。

进阶:运行时改键

func remap_jump_to(key: InputEventKey):
    InputMap.action_erase_events("jump")
    InputMap.action_add_event("jump", key)
    ProjectSettings.save()  # 如需持久化
  • 可配合设置面板,让玩家自定义键位;记得在 UI 中提示“按任意键捕获”。

进阶:输入缓冲与踩空容错

  • 结合动作查询可做缓冲:
var jump_buffer := 0.2
var last_jump_press := -1.0

func _process(delta):
    if Input.is_action_just_pressed("jump"):
        last_jump_press = 0
    if last_jump_press >= 0:
        last_jump_press += delta
    if last_jump_press <= jump_buffer and is_on_floor():
        do_jump()
        last_jump_press = -1
  • 通过动作名实现统一缓冲,键鼠/手柄都适用。

总结复盘

  • 记牢动作优先:先在 Input Map 定义“动作名”,代码只读动作,不写具体键。
  • 常用 API:is_action_pressed/just_pressedget_axis/get_vectoraction_press/release(虚拟输入)。
  • 排查从三处开始:动作是否存在、事件是否录入、是否被 UI 捕获。做到这些,键鼠/手柄/触摸即可一套代码通吃。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术小甜甜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值