推荐使用的Unity插件(InputSystem)

发布于:2025-06-19 ⋅ 阅读:(16) ⋅ 点赞:(0)

本文将提供更简洁的步骤和常见问题解决。

一、极简入门步骤:

  1. 安装:Package Manager中安装Input System(确保Unity版本在2019.4+)

  2. 创建Input Actions

  • 在Project窗口右键 -> Create -> Input Actions

  • 双击打开编辑器,添加Action Map(例如"Player")

  • 在Action Map中添加Action(例如"Move"、“Jump”)

  • 为每个Action添加绑定,例如:

  • “Move”:绑定到/leftStick 和 /wasd

  • “Jump”:绑定到/space 和 /buttonSouth

  1. 生成C#类
  • 在Input Actions资源的Inspector中,勾选"Generate C# Class"

  • 点击"Apply",生成一个与资源同名的C#脚本

  1. 在代码中使用

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;

}

}

  1. 使用PlayerInput组件(可选)
  • 将Input Actions资源拖到PlayerInput组件的"Actions"属性

  • 选择行为模式(如"Invoke Unity Events")并配置事件

常见问题及解决:

  1. 输入不生效
  • 检查是否启用了Action Map:inputActions.Player.Enable();

  • 检查Project Settings中Active Input Handling是否选择了"Input System Package"

  • 重启Unity(有时安装后需要重启)

  1. 如何在多个脚本中使用同一个输入
  • 推荐创建一个单例管理输入,或者将Input Actions实例作为参数传递给其他脚本
  1. 如何实现双人游戏
  • 使用PlayerInputManager组件

  • 在场景中添加一个空物体,挂载PlayerInputManager

  • 设置玩家预制体(Prefab),在预制体上添加PlayerInput组件并配置Input Actions

  • 通过PlayerInputManager动态创建玩家实例

  1. 如何实现按键重绑定

// 找到要重绑定的Action

var action = inputActions.FindAction("Player/Jump");

// 开始重绑定

var rebindOperation = action.PerformInteractiveRebinding()

.WithControlsExcluding("<Mouse>/press")

.OnMatchWaitForAnother(0.1f)

.Start();

  1. 如何切换操作方案(如行走和驾驶)
  • 使用不同的Action Map

  • 切换时禁用当前Action Map,启用另一个:


inputActions.Player.Disable();

inputActions.Vehicle.Enable();

  1. 如何获取当前设备类型(判断是手柄还是键盘)

// 通过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 的新输入系统提供了更强大、灵活的输入处理方式,下面我将通过一个完整的示例项目展示如何使用它。

安装与设置

  1. 安装 Input System

    • 打开 Package Manager (Window > Package Manager)
    • 选择 “Unity Registry”
    • 找到 “Input System” 并安装
  2. 启用新输入系统

    • 前往 Edit > Project Settings > Player
    • 在 “Other Settings” 部分:
      • Active Input Handling: 选择 “Input System Package (New)”

创建输入配置

步骤 1:创建 Input Actions Asset

  1. 在 Project 窗口右键 > Create > Input Actions
  2. 命名为 “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;
        }
    }
}

最佳实践与技巧

  1. 输入处理模式选择

    • 对于简单项目:使用 Invoke Unity Events 模式
    • 对于复杂项目:使用 Invoke C# Events 或直接访问输入动作
  2. 输入动作组织

    • 按功能分组(Player、UI、Vehicle等)
    • 为常用操作设置复合绑定(如WASD绑定为2D向量)
  3. 多玩家输入

    // 在玩家加入时
    public void OnPlayerJoined(PlayerInput playerInput)
    {
        // 为每个玩家设置不同的输入设备
        if (playerInput.playerIndex == 0)
        {
            playerInput.SwitchCurrentControlScheme("KeyboardMouse", Keyboard.current);
        }
        else
        {
            playerInput.SwitchCurrentControlScheme("Gamepad", Gamepad.current);
        }
    }
    
  4. 输入处理优化

    • 使用 InputAction.CallbackContext 代替每帧检查
    • 在不需要时禁用输入动作以节省资源
  5. 移动设备支持

    • 使用 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();
    }
    

调试技巧

  1. 使用 Input Debugger:

    • Window > Analysis > Input Debugger
    • 实时查看所有输入设备状态
  2. 在编辑器中模拟设备:

    • 打开 Input Debugger
    • 点击 “Add Device” 添加虚拟设备
    • 使用虚拟设备测试输入
  3. 记录输入事件:

    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的核心功能和使用方法。根据你的项目需求选择合适的实现方式,并记得在复杂项目中合理组织输入动作和绑定。


网站公告

今日签到

点亮在社区的每一天
去签到