本文将提供更简洁的步骤和常见问题解决。
一、极简入门步骤:
安装:Package Manager中安装Input System(确保Unity版本在2019.4+)
创建Input Actions:
在Project窗口右键 -> Create -> Input Actions
双击打开编辑器,添加Action Map(例如"Player")
在Action Map中添加Action(例如"Move"、“Jump”)
为每个Action添加绑定,例如:
“Move”:绑定到/leftStick 和 /wasd
“Jump”:绑定到/space 和 /buttonSouth
- 生成C#类:
在Input Actions资源的Inspector中,勾选"Generate C# Class"
点击"Apply",生成一个与资源同名的C#脚本
- 在代码中使用:
using UnityEngine;
using UnityEngine.InputSystem;
public class Example : MonoBehaviour
{
private PlayerInputActions inputActions;
void Awake()
{
inputActions = new PlayerInputActions();
inputActions.Player.Enable();
}
void Update()
{
Vector2 move = inputActions.Player.Move.ReadValue<Vector2>();
// 使用move移动角色
}
void OnJumpPerformed(InputAction.CallbackContext context)
{
// 跳跃
}
void OnEnable()
{
inputActions.Player.Jump.performed += OnJumpPerformed;
}
void OnDisable()
{
inputActions.Player.Jump.performed -= OnJumpPerformed;
}
}
- 使用PlayerInput组件(可选):
将Input Actions资源拖到PlayerInput组件的"Actions"属性
选择行为模式(如"Invoke Unity Events")并配置事件
常见问题及解决:
- 输入不生效:
检查是否启用了Action Map:
inputActions.Player.Enable();
检查Project Settings中Active Input Handling是否选择了"Input System Package"
重启Unity(有时安装后需要重启)
- 如何在多个脚本中使用同一个输入?
- 推荐创建一个单例管理输入,或者将Input Actions实例作为参数传递给其他脚本
- 如何实现双人游戏?
使用
PlayerInputManager
组件在场景中添加一个空物体,挂载
PlayerInputManager
设置玩家预制体(Prefab),在预制体上添加
PlayerInput
组件并配置Input Actions通过
PlayerInputManager
动态创建玩家实例
- 如何实现按键重绑定?
// 找到要重绑定的Action
var action = inputActions.FindAction("Player/Jump");
// 开始重绑定
var rebindOperation = action.PerformInteractiveRebinding()
.WithControlsExcluding("<Mouse>/press")
.OnMatchWaitForAnother(0.1f)
.Start();
- 如何切换操作方案(如行走和驾驶)?
使用不同的Action Map
切换时禁用当前Action Map,启用另一个:
inputActions.Player.Disable();
inputActions.Vehicle.Enable();
- 如何获取当前设备类型(判断是手柄还是键盘)?
// 通过PlayerInput组件
PlayerInput playerInput = GetComponent<PlayerInput>();
string deviceType = playerInput.currentControlScheme;
// 或者监听设备变化
playerInput.onControlsChanged += (PlayerInput input) =>
{
Debug.Log(input.currentControlScheme);
};
调试技巧:
打开菜单:Window -> Analysis -> Input Debugger,查看实时输入
在代码中监听输入事件,打印日志
希望这个快速指南能解决你的问题!如果遇到特定问题,请提供更多细节。
二、Unity Input System 全面使用指南
Unity 的新输入系统提供了更强大、灵活的输入处理方式,下面我将通过一个完整的示例项目展示如何使用它。
安装与设置
安装 Input System:
- 打开 Package Manager (Window > Package Manager)
- 选择 “Unity Registry”
- 找到 “Input System” 并安装
启用新输入系统:
- 前往 Edit > Project Settings > Player
- 在 “Other Settings” 部分:
- Active Input Handling: 选择 “Input System Package (New)”
创建输入配置
步骤 1:创建 Input Actions Asset
- 在 Project 窗口右键 > Create > Input Actions
- 命名为 “PlayerControls”
步骤 2:配置输入动作
双击打开 PlayerControls 进行编辑:
Action Map | Action | Binding | Control Path |
---|---|---|---|
Player | Move | 2D Vector | WASD / Left Stick |
Player | Jump | Button | Space / Gamepad South |
Player | Look | 2D Vector | Mouse Delta / Right Stick |
Player | Fire | Button | Mouse Left / Gamepad East |
UI | Navigate | 2D Vector | Arrow Keys / Left Stick |
UI | Submit | Button | Enter / Gamepad South |
代码实现
基础移动控制器
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(CharacterController))]
public class PlayerController : MonoBehaviour
{
[Header("Movement Settings")]
[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float jumpHeight = 2f;
[SerializeField] private float gravity = -9.81f;
[SerializeField] private float rotationSpeed = 10f;
[Header("Camera")]
[SerializeField] private Transform cameraTransform;
private CharacterController controller;
private PlayerInput playerInput;
private InputAction moveAction;
private InputAction jumpAction;
private InputAction lookAction;
private Vector3 velocity;
private bool isGrounded;
private float rotationX = 0f;
private void Awake()
{
controller = GetComponent<CharacterController>();
playerInput = GetComponent<PlayerInput>();
// 获取输入动作
moveAction = playerInput.actions["Move"];
jumpAction = playerInput.actions["Jump"];
lookAction = playerInput.actions["Look"];
// 锁定鼠标
Cursor.lockState = CursorLockMode.Locked;
}
private void Update()
{
// 地面检测
isGrounded = controller.isGrounded;
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
// 移动
Vector2 moveInput = moveAction.ReadValue<Vector2>();
Vector3 moveDirection = new Vector3(moveInput.x, 0, moveInput.y);
moveDirection = Quaternion.Euler(0, cameraTransform.eulerAngles.y, 0) * moveDirection;
controller.Move(moveDirection * moveSpeed * Time.deltaTime);
// 跳跃
if (jumpAction.triggered && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
// 重力
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
// 视角旋转
Vector2 lookInput = lookAction.ReadValue<Vector2>();
float mouseX = lookInput.x * rotationSpeed * Time.deltaTime;
float mouseY = lookInput.y * rotationSpeed * Time.deltaTime;
rotationX -= mouseY;
rotationX = Mathf.Clamp(rotationX, -90f, 90f);
cameraTransform.localRotation = Quaternion.Euler(rotationX, 0, 0);
transform.Rotate(Vector3.up * mouseX);
}
}
UI 输入处理
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class UIController : MonoBehaviour
{
[SerializeField] private Button startButton;
[SerializeField] private Slider volumeSlider;
private PlayerInput playerInput;
private InputAction navigateAction;
private InputAction submitAction;
private void Awake()
{
playerInput = GetComponent<PlayerInput>();
// 切换到UI输入映射
playerInput.SwitchCurrentActionMap("UI");
// 获取输入动作
navigateAction = playerInput.actions["Navigate"];
submitAction = playerInput.actions["Submit"];
// 注册输入事件
navigateAction.performed += OnNavigate;
submitAction.performed += OnSubmit;
}
private void OnNavigate(InputAction.CallbackContext context)
{
Vector2 direction = context.ReadValue<Vector2>();
// 简单的UI导航逻辑
if (Mathf.Abs(direction.y) > 0.5f)
{
if (direction.y > 0) volumeSlider.Select();
else startButton.Select();
}
}
private void OnSubmit(InputAction.CallbackContext context)
{
// 模拟按钮点击
if (startButton.gameObject == UnityEngine.EventSystems.EventSystem.current.currentSelectedGameObject)
{
startButton.onClick.Invoke();
}
}
private void OnDestroy()
{
navigateAction.performed -= OnNavigate;
submitAction.performed -= OnSubmit;
}
}
高级功能实现
输入重绑定系统
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class RebindManager : MonoBehaviour
{
[SerializeField] private InputActionReference targetAction;
[SerializeField] private Text bindingText;
[SerializeField] private GameObject waitingPanel;
private InputActionRebindingExtensions.RebindingOperation rebindingOperation;
public void StartRebinding()
{
waitingPanel.SetActive(true);
bindingText.text = "Press any key...";
// 取消当前绑定
targetAction.action.Disable();
// 开始重绑定
rebindingOperation = targetAction.action.PerformInteractiveRebinding()
.WithControlsExcluding("<Mouse>/position")
.WithControlsExcluding("<Mouse>/delta")
.WithControlsExcluding("<Gamepad>/Start")
.OnMatchWaitForAnother(0.1f)
.OnComplete(operation => RebindComplete())
.Start();
}
private void RebindComplete()
{
// 保存新绑定
string rebinds = rebindingOperation.action.SaveBindingOverridesAsJson();
PlayerPrefs.SetString("rebinds", rebinds);
// 更新UI显示
bindingText.text = InputControlPath.ToHumanReadableString(
targetAction.action.bindings[0].effectivePath,
InputControlPath.HumanReadableStringOptions.OmitDevice);
// 清理操作
rebindingOperation.Dispose();
waitingPanel.SetActive(false);
targetAction.action.Enable();
}
private void OnEnable()
{
// 加载保存的重绑定
if (PlayerPrefs.HasKey("rebinds"))
{
string rebinds = PlayerPrefs.GetString("rebinds");
targetAction.action.LoadBindingOverridesFromJson(rebinds);
}
// 初始化显示
bindingText.text = InputControlPath.ToHumanReadableString(
targetAction.action.bindings[0].effectivePath,
InputControlPath.HumanReadableStringOptions.OmitDevice);
}
}
设备检测与切换
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;
public class DeviceDisplay : MonoBehaviour
{
[SerializeField] private Text deviceText;
[SerializeField] private Image keyboardIcon;
[SerializeField] private Image gamepadIcon;
private PlayerInput playerInput;
private void Awake()
{
playerInput = FindObjectOfType<PlayerInput>();
playerInput.onControlsChanged += OnControlsChanged;
UpdateDeviceDisplay();
}
private void OnControlsChanged(PlayerInput input)
{
UpdateDeviceDisplay();
}
private void UpdateDeviceDisplay()
{
string deviceName = "Unknown";
if (playerInput.currentControlScheme == "KeyboardMouse")
{
deviceName = "Keyboard & Mouse";
keyboardIcon.gameObject.SetActive(true);
gamepadIcon.gameObject.SetActive(false);
}
else if (playerInput.currentControlScheme == "Gamepad")
{
deviceName = "Gamepad";
keyboardIcon.gameObject.SetActive(false);
gamepadIcon.gameObject.SetActive(true);
}
deviceText.text = $"Current Device: {deviceName}";
}
private void OnDestroy()
{
if (playerInput != null)
{
playerInput.onControlsChanged -= OnControlsChanged;
}
}
}
最佳实践与技巧
输入处理模式选择:
- 对于简单项目:使用
Invoke Unity Events
模式 - 对于复杂项目:使用
Invoke C# Events
或直接访问输入动作
- 对于简单项目:使用
输入动作组织:
- 按功能分组(Player、UI、Vehicle等)
- 为常用操作设置复合绑定(如WASD绑定为2D向量)
多玩家输入:
// 在玩家加入时 public void OnPlayerJoined(PlayerInput playerInput) { // 为每个玩家设置不同的输入设备 if (playerInput.playerIndex == 0) { playerInput.SwitchCurrentControlScheme("KeyboardMouse", Keyboard.current); } else { playerInput.SwitchCurrentControlScheme("Gamepad", Gamepad.current); } }
输入处理优化:
- 使用
InputAction.CallbackContext
代替每帧检查 - 在不需要时禁用输入动作以节省资源
- 使用
移动设备支持:
- 使用
Touchscreen
输入 - 添加虚拟摇杆和按钮
// 在Input Actions中创建触摸输入 public void SetupTouchControls() { // 添加触摸输入动作 var touchAction = new InputAction("TouchPosition", binding: "<Touchscreen>/position"); touchAction.Enable(); // 添加点击动作 var tapAction = new InputAction("PrimaryTouch", binding: "<Touchscreen>/primaryTouch/tap"); tapAction.Enable(); }
- 使用
调试技巧
使用 Input Debugger:
- Window > Analysis > Input Debugger
- 实时查看所有输入设备状态
在编辑器中模拟设备:
- 打开 Input Debugger
- 点击 “Add Device” 添加虚拟设备
- 使用虚拟设备测试输入
记录输入事件:
private void OnEnable() { InputSystem.onEvent += OnInputEvent; } private void OnDisable() { InputSystem.onEvent -= OnInputEvent; } private void OnInputEvent(InputEventPtr eventPtr, InputDevice device) { // 记录输入事件 Debug.Log($"Input event from {device.name}"); }
这个全面的指南覆盖了Unity Input System的核心功能和使用方法。根据你的项目需求选择合适的实现方式,并记得在复杂项目中合理组织输入动作和绑定。