本文将提供更简洁的步骤和常见问题解决。
一、极简入门步骤:
-
安装: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
动态创建玩家实例
- 如何实现按键重绑定?
// 找到要重绑定的Actionvar 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的核心功能和使用方法。根据你的项目需求选择合适的实现方式,并记得在复杂项目中合理组织输入动作和绑定。