关于 unity-input
unity-input 是面向 Unity 开发者的 Input System 指南,介绍基于动作的输入配置与读取,以及与旧版输入管理器的区别。内容涵盖多设备输入、本地多人、交互、触控和运行时重绑定。
主要功能
- 01InputAction 与 Action Map
- 02PlayerInput 本地多人管理
- 03轮询与事件回调读取输入
- 04键盘、手柄、鼠标和触控
- 05输入交互与处理器
- 06运行时重绑定和设备发现
适用场景
- 01配置跨设备的玩家操作
- 02在游戏与 UI 输入映射间切换
- 03实现本地多人设备分配
- 04添加运行时按键重绑定
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ nice-wolf-studio/ unity-claude-skills --skill unity-input安装后在 Claude Code 中输入/unity-input确认已加载。
附带文件references/input-system-api.md
详细介绍
Unity Input System
Input System 概述:新系统与旧系统
Unity 提供两种输入系统:
| 功能 | 新 Input System(推荐) | 旧版 Input Manager |
|---|---|---|
| 包 | com.unity.inputsystem(Unity 6.3 对应 v1.19.0) | 内置(UnityEngine.Input) |
| 架构 | 基于操作、事件驱动 | 基于轮询 |
| 设备支持 | 游戏手柄、键盘、鼠标、触控、XR、自定义设备 | 键盘、鼠标、摇杆 |
| 多人游戏 | 通过 PlayerInput 内置本地多人游戏支持 | 手动实现 |
| 重新绑定 | 支持运行时重新绑定 | 不支持 |
| 跨平台 | 按设备类型配置 Control Scheme | 手动编写各平台代码 |
新的 Input System 是通过 Package Manager 安装的包。它以基于操作的模型取代旧版 Input.GetKey/Input.GetAxis API,将输入用途与设备控件分离。
命名空间: UnityEngine.InputSystem
快速入门设置
1. 安装包
通过 Window > Package Manager > Unity Registry > Input System 安装。
2. 创建默认的项目级操作
前往 Edit > Project Settings > Input System Package > Input Actions,然后点击 "Create and assign a default project-wide Action Asset"。
这会创建默认的 Action Map:
- Player:移动、视角、跳跃、攻击
- UI:导航、提交、取消
每个操作都包含键盘、游戏手柄、XR 控制器和触摸屏的绑定。
3. 在脚本中读取输入
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
InputAction moveAction;
InputAction jumpAction;
void Start()
{
moveAction = InputSystem.actions.FindAction("Move");
jumpAction = InputSystem.actions.FindAction("Jump");
}
void Update()
{
Vector2 moveValue = moveAction.ReadValue<Vector2>();
transform.Translate(new Vector3(moveValue.x, 0, moveValue.y) * Time.deltaTime * 5f);
if (jumpAction.IsPressed())
{
// Jump logic
}
}
}
如果多个地图中存在同名操作,请同时指定两者:"Player/Move"。
Input Actions 和 Action Maps
核心概念
- InputAction:有名称的操作,可返回控件值或触发回调
- InputActionMap:相关操作的命名集合(例如 "Player"、"UI"、"Vehicle")
- InputBinding:操作与设备控件之间的关联
- InputSystem.actions:对项目级操作的引用
创建操作
方法 1 — Input Actions Editor(推荐): 通过 Project Settings 进行配置 > Input System Package。
方法 2 — MonoBehaviour 字段: 直接在脚本中声明 InputAction 字段(可在 Inspector 中配置)。
方法 3 — 代码:
var moveAction = new InputAction("Move", InputActionType.Value);
moveAction.AddCompositeBinding("Dpad")
.With("Up", "<Keyboard>/w").With("Down", "<Keyboard>/s")
.With("Left", "<Keyboard>/a").With("Right", "<Keyboard>/d");
moveAction.Enable();
方法 4 — JSON: var map = InputActionMap.FromJson(jsonString);
操作生命周期
操作初始状态为禁用。必须调用 .Enable() 才能响应输入。启用时无法修改绑定;请先调用 .Disable()。
Input Action 资源(.inputactions)
这些 JSON 文件用于存储操作、绑定和控制方案。通过 Assets > Create > Input Actions 创建。
自动生成的 C# 类: 在资源的导入器中启用 "Generate C# Class",即可获得类型安全的访问方式:
public class MyPlayerScript : MonoBehaviour, IGameplayActions
{
MyPlayerControls controls;
public void OnEnable()
{
controls = new MyPlayerControls();
controls.gameplay.SetCallbacks(this);
controls.gameplay.Enable();
}
public void OnDisable()
{
controls.gameplay.Disable();
}
public void OnMove(InputAction.CallbackContext context)
{
Vector2 move = context.ReadValue<Vector2>();
// Handle movement
}
}
PlayerInput 组件
PlayerInput 组件将 Input Actions 映射到脚本方法,并通过设备筛选和屏幕分割处理本地多人游戏。
设置
- 将
PlayerInput组件添加到玩家 GameObject - 将 Action Asset 分配给 Actions 字段
- 选择一个 Default Action Map
- 选择一种 Behavior 通知类型
Behavior 选项
| Behavior | 机制 | 最适用于 |
|---|---|---|
| Send Messages | GameObject.SendMessage() | 简单原型开发 |
| Broadcast Messages | 沿层级调用 BroadcastMessage() | 组件层级结构 |
| Invoke Unity Events | 在 Inspector 中配置事件路由 | 便于设计师连线 |
| Invoke C# Events | onActionTriggered、onDeviceLost、onDeviceRegained | 由程序员控制 |
Send Messages 模式
public class PlayerActions : MonoBehaviour
{
public void OnJump()
{
// Called when Jump action triggers (no parameters)
}
public void OnMove(InputValue value)
{
Vector2 v = value.Get<Vector2>();
// InputValue is only valid during this callback
}
}
Unity Events 模式
public void OnFire(InputAction.CallbackContext context)
{
if (context.performed)
{
// Fire logic
}
}
管理 PlayerInput
PlayerInput playerInput = GetComponent<PlayerInput>();
playerInput.DeactivateInput(); // Disable all input
playerInput.ActivateInput(); // Re-enable with default map
playerInput.SwitchCurrentActionMap("Vehicle"); // Switch action map
在代码中读取输入
轮询(在 Update 中)
// 2D movement axis
Vector2 move = moveAction.ReadValue<Vector2>();
// Button state
if (jumpAction.IsPressed()) { /* held down */ }
if (jumpAction.WasPressedThisFrame()) { /* just pressed */ }
if (jumpAction.WasReleasedThisFrame()) { /* just released */ }
回调(事件驱动)
void OnEnable()
{
fireAction.started += OnFireStarted;
fireAction.performed += OnFirePerformed;
fireAction.canceled += OnFireCanceled;
fireAction.Enable();
}
void OnDisable()
{
fireAction.started -= OnFireStarted;
fireAction.performed -= OnFirePerformed;
fireAction.canceled -= OnFireCanceled;
fireAction.Disable();
}
void OnFireStarted(InputAction.CallbackContext ctx) { /* Input began */ }
void OnFirePerformed(InputAction.CallbackContext ctx) { /* Completed */ }
void OnFireCanceled(InputAction.CallbackContext ctx) { /* Interrupted */ }
游戏手柄 / 键盘 / 鼠标 / 触控
游戏手柄
using UnityEngine.InputSystem;
// Current gamepad (null if none connected)
var gp = Gamepad.current;
if (gp == null) return;
Vector2 leftStick = gp.leftStick.ReadValue();
bool southPressed = gp.buttonSouth.isPressed;
// Access by enum
gp[GamepadButton.LeftShoulder].isPressed;
gp[GamepadButton.Y].isPressed; // Xbox style
gp[GamepadButton.Triangle].isPressed; // PlayStation style
// Rumble / Haptics
gp.SetMotorSpeeds(0.25f, 0.75f); // low-frequency, high-frequency
gp.ResetHaptics();
// Global haptics control
InputSystem.PauseHaptics();
InputSystem.ResumeHaptics();
InputSystem.ResetHaptics();
支持的游戏手柄:DualShock 3/4、DualSense、Xbox(XInput/Bluetooth)、Switch Pro。通用 HID 游戏手柄会显示为通用摇杆,而非 Gamepad 设备。
键盘和鼠标
var kb = Keyboard.current;
if (kb.spaceKey.wasPressedThisFrame) { /* space pressed */ }
var mouse = Mouse.current;
Vector2 mousePos = mouse.position.ReadValue();
float scroll = mouse.scroll.ReadValue().y;
bool leftClick = mouse.leftButton.isPressed;
触控
两个 API 级别:
低级 — 触摸屏设备:
var ts = Touchscreen.current;
if (ts.primaryTouch.press.isPressed)
{
Vector2 pos = ts.primaryTouch.position.ReadValue();
}
高级 — EnhancedTouch API:
using UnityEngine.InputSystem.EnhancedTouch;
void OnEnable() => EnhancedTouchSupport.Enable();
void OnDisable() => EnhancedTouchSupport.Disable();
void Update()
{
foreach (var touch in Touch.activeTouches)
{
Debug.Log($"{touch.touchId}: {touch.screenPosition}, {touch.phase}");
}
}
触控阶段:Began、Moved、Stationary、Ended、Cancelled。
使用 Actions 实现多点触控: 绑定 <Touchscreen>/touch*/press,并将 action 类型设为 PassThrough,即可接收每次触控的回调。
触控模拟: 在开发期间,通过 TouchSimulation.Enable() 启用鼠标/触控笔的触控模拟。
设备发现
// Monitor device connections
InputSystem.onDeviceChange += (device, change) =>
{
if (change == InputDeviceChange.Added)
Debug.Log($"Device connected: {device.displayName}");
};
交互和处理器
交互定义了驱动 action 阶段的输入模式。
交互阶段
| 阶段 | 含义 |
|---|---|
| Waiting | 等待输入 |
| Started | 已接收输入,但尚未完成 |
| Performed | 交互完成 — 主要响应触发点 |
| Canceled | 交互已中断 |
内置交互
| 交互 | 说明 | 关键参数 |
|---|---|---|
| Default | 自动应用;行为因 action 类型而异 | — |
| Press | 明确的按钮按下行为 | pressPoint、behavior(PressOnly/ReleaseOnly/PressAndRelease) |
| Hold | 持续按下达到最短时长 | duration、pressPoint |
| Tap | 快速按下并释放 | duration、pressPoint |
| SlowTap | 按住后释放 | duration、pressPoint |
| MultiTap | 重复点击序列 | tapTime、tapDelay、tapCount、pressPoint |
通过代码添加交互
var action = new InputAction("fire");
action.AddBinding("<Gamepad>/buttonSouth")
.WithInteractions("tap(duration=0.8)");
点击与按住示例(开火与蓄力)
var fireAction = new InputAction("fire");
fireAction.AddBinding("<Gamepad>/buttonSouth").WithInteractions("tap,slowTap");
fireAction.started += ctx => { if (ctx.interaction is SlowTapInteraction) ShowChargingUI(); };
fireAction.performed += ctx => {
if (ctx.interaction is SlowTapInteraction) ChargedFire(); else Fire();
};
fireAction.canceled += _ => HideChargingUI();
fireAction.Enable();
自定义交互
实现 IInputInteraction,然后注册:InputSystem.RegisterInteraction<T>()。完整示例请参阅 references/input-system-api.md。
常见模式
切换 Action Map(例如,游戏玩法与 UI)
public class GameStateManager : MonoBehaviour
{
PlayerInput playerInput;
void Start() => playerInput = GetComponent<PlayerInput>();
public void EnterMenu() => playerInput.SwitchCurrentActionMap("UI");
public void ExitMenu() => playerInput.SwitchCurrentActionMap("Player");
}
运行时重新绑定
var rebindOp = action.PerformInteractiveRebinding()
.WithControlsExcluding("Mouse")
.OnMatchWaitForAnother(0.1f)
.OnComplete(op =>
{
Debug.Log($"Rebound to: {op.action.bindings[0].effectivePath}");
op.Dispose();
})
.Start();
为同一个 Action 添加多个绑定(WASD + 方向键)
var moveAction = new InputAction("Move", InputActionType.Value);
moveAction.AddCompositeBinding("2DVector")
.With("Up", "<Keyboard>/w").With("Down", "<Keyboard>/s")
.With("Left", "<Keyboard>/a").With("Right", "<Keyboard>/d");
moveAction.AddCompositeBinding("2DVector")
.With("Up", "<Keyboard>/upArrow").With("Down", "<Keyboard>/downArrow")
.With("Left", "<Keyboard>/leftArrow").With("Right", "<Keyboard>/rightArrow");
反模式
| 反模式 | 问题 | 正确做法 |
|---|---|---|
使用 Input.GetKey()(旧版) | 与新版 Input System 不兼容;不支持重新绑定和多设备 | 使用带绑定的 InputAction |
未调用 .Enable() 就读取 Actions | Actions 初始处于禁用状态,不会返回任何值 | 始终在 OnEnable() 中调用 action.Enable() |
清理时忘记调用 .Disable() | 导致内存泄漏和幽灵回调 | 在 OnDisable() 中调用 action.Disable() |
| action 启用时修改绑定 | 会引发异常 | 修改前调用 .Disable(),然后再调用 .Enable() |
| 在游戏玩法代码中硬编码设备路径 | 破坏跨平台支持 | 改用 Actions + Control Schemes |
在回调之外使用 InputValue | 该值仅在回调帧内有效 | 立即将该值复制到字段中 |
不做空值检查就访问 Gamepad.current | 未连接游戏手柄时会崩溃 | 始终检查 if (Gamepad.current == null) return; |
| 不取消订阅 action 回调 | 场景重新加载时会导致错误 | 在 OnDisable() 中取消订阅 |
在生产环境中使用 SendMessages 行为 | 反射会带来性能开销 | 使用 Invoke Unity Events 或 Invoke C# Events |
| 未启用 EnhancedTouch 就对其进行轮询 | 返回空集合 | 首先调用 EnhancedTouchSupport.Enable() |
API 快速参考
| API | 用途 |
|---|---|
InputSystem.actions | 全项目范围的操作 |
InputSystem.actions.FindAction("name") | 按名称查找操作 |
action.ReadValue<T>() | 读取当前值 |
action.IsPressed() | 检查按钮是否按住 |
action.WasPressedThisFrame() | 检查按钮是否刚刚按下 |
action.WasReleasedThisFrame() | 检查按钮是否刚刚释放 |
action.Enable() / action.Disable() | 启用/停用 |
action.started / performed / canceled | 回调事件 |
action.AddBinding("path") | 在代码中添加绑定 |
action.AddCompositeBinding("type") | 添加复合绑定(Dpad、2DVector) |
.WithInteractions("tap(duration=0.5)") | 为绑定添加交互 |
Gamepad.current | 当前游戏手柄引用 |
Keyboard.current / Mouse.current | 当前键盘/鼠标 |
Touchscreen.current | 当前触摸屏 |
EnhancedTouchSupport.Enable() | 启用增强触摸 API |
Touch.activeTouches | 所有活动触摸(增强模式) |
InputSystem.onDeviceChange | 设备连接事件 |
PlayerInput.SwitchCurrentActionMap() | 更改当前活动的操作映射 |
action.PerformInteractiveRebinding() | 开始运行时重新绑定 |
相关技能
- unity-scripting — MonoBehaviour 生命周期、C# 模式
- unity-ui — UI Toolkit 输入集成、
InputSystemUIInputModule - unity-xr — XR 控制器输入、追踪设备