Input System
Unity 的现代 Input System 包提供灵活重映射、多设备支持与事件驱动 Action,全面取代旧式 Input.GetKey() 轮询 API。适合手柄、触控与键鼠并存的跨平台项目,帮助程序用 Input Actions 资产统一绑定输入,并更易实现本地化按键提示与无障碍输入配置方案。
想象一下...
旧 Input System 像员工每 0.016 秒打电话问“有顾客吗?”(轮询)。新 Input System 装了门铃(事件)——只有有人按铃你才听见。Action Maps 像调度板——同一个“Confirm”在菜单里是 Navigate Accept,在玩法里是 Jump。不需要 `if (context == menu)` 意大利面代码。
概念详解
Input Actions Asset 是一个
.inputactions 文件,保存所有绑定。它组织为
Action Maps(Gameplay、UI、Vehicle…)→ 每个 Map 有
Actions(Move、Jump、Fire…)→ 每个 Action 有
Bindings(按键、摇杆、手柄按钮…)。
事件驱动:订阅
action.started、action.performed、action.canceled。用
context.ReadValue<Vector2>() 读取值。不必在 Update 中轮询。
Player Input 组件:挂到 GameObject 上可自动接线事件。 支持 Messages、C# Events 或 Unity Events。
运行时重映射:
action.AddBinding() 和
InputActionRebindingExtensions.PerformInteractiveRebinding() 让玩家能在
Settings 菜单中改键位。
示意图:Input System 架构
Input Actions Asset (.inputactions)
Actions: Move, Jump, Fire, Interact...
started / performed / canceled events
PlayerController
OnMove(ctx)
UINavigator
OnNavigate(ctx)
VehicleDriver
OnSteer(ctx)
动手步骤
安装 Input System 包
Window → Package Manager → Input System → Install。按提示重启。
创建 Input Actions Asset
Assets → Create → Input Actions。添加 Action Maps、Actions,以及每个键/按钮的 Bindings。
生成 C# 类
选中 .inputactions 文件 → Inspector → 勾选 "Generate C# Class" → Apply → Unity 生成包装类。
订阅 / 取消订阅事件
OnEnable:_actions.Gameplay.Jump.performed += OnJump; OnDisable:用同样方式取消订阅。
交互模拟器
按键(或下方按钮),观察事件到达当前活动 Action Map 的正确监听者。
Virtual Input
Event Log
按键查看事件...
代码示例
基础使用生成的 C# 类并订阅事件。
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
private GameControls _actions; // Generated C# class
private Rigidbody _rb;
private Vector2 _moveInput;
void Awake()
{
_rb = GetComponent<Rigidbody>();
_actions = new GameControls();
}
void OnEnable()
{
_actions.Gameplay.Enable();
_actions.Gameplay.Move.performed += OnMove;
_actions.Gameplay.Move.canceled += OnMove;
_actions.Gameplay.Jump.performed += OnJump;
}
void OnDisable()
{
_actions.Gameplay.Move.performed -= OnMove;
_actions.Gameplay.Move.canceled -= OnMove;
_actions.Gameplay.Jump.performed -= OnJump;
_actions.Gameplay.Disable();
}
void OnMove(InputAction.CallbackContext ctx)
=> _moveInput = ctx.ReadValue<Vector2>();
void OnJump(InputAction.CallbackContext ctx)
=> _rb.AddForce(Vector3.up * 5f, ForceMode.Impulse);
void FixedUpdate()
=> _rb.velocity = new Vector3(_moveInput.x * 5f, _rb.velocity.y, _moveInput.y * 5f);
}代码示例
进阶交互式重绑定——让玩家在运行时改键位。
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;
public class KeyRebinder : MonoBehaviour
{
[SerializeField] private InputActionReference jumpAction;
[SerializeField] private TextMeshProUGUI bindingLabel;
private InputActionRebindingExtensions.RebindingOperation _rebindOp;
public void StartRebind()
{
jumpAction.action.Disable();
bindingLabel.text = "Press any key...";
_rebindOp = jumpAction.action
.PerformInteractiveRebinding()
.WithControlsExcluding("Mouse")
.OnMatchWaitForAnother(0.1f)
.OnComplete(op => {
op.Dispose();
jumpAction.action.Enable();
bindingLabel.text = InputControlPath.ToHumanReadableString(
jumpAction.action.bindings[0].effectivePath);
// Persist binding overrides
PlayerPrefs.SetString("JumpBinding", jumpAction.action.SaveBindingOverridesAsJson());
})
.Start();
}
}📌 快速记忆
- ▸按上下文 Enable/Disable ActionMaps(Gameplay ↔ UI)
- ▸在 OnEnable 订阅,在 OnDisable 取消订阅
- ▸
performed= 按下;canceled= 松开 - ▸生成 C# 类 → 更清晰的 API + IntelliSense
⚠️ 常见错误
❌ 忘记对 Action Map 调用 Enable()
即使订阅了 Actions 也不会触发——静默失败
✅ 在 OnEnable 中调用 _actions.Gameplay.Enable()
❌ 在 OnDisable 中忘记 Unsubscribe
内存泄漏——事件会调用到已销毁的对象
✅ 始终用 OnEnable/OnDisable 成对 Subscribe/Unsubscribe