3.2 输入系统 (Input) 三、Unity 核心模块 3.2 输入系统 (Input) 在游戏开发中,输入是玩家与游戏世界交互的桥梁。Unity 的输入系统负责捕捉来自各种输入设备(如键盘、鼠标、手柄、触摸屏等)的信号,并将这些信号转化为游戏逻辑可以理解和响应的事件和数据。一个高效、灵活且易于使用的输入系统对于构建流畅、沉浸式的游戏体验至关重要。 本章节将深入探讨 Unity 的新输入系统 (Input System),这是 Unity 推荐的现代输入解决方案,它提供了比旧输入管理器 (Input Manager) 更强大、更灵活的功能。我们将从基本概念入手,逐步深入到高级用法,并通过代码示例和图表帮助您全面掌握 Unity 的输入系统。 3.2.
在游戏开发中,输入是玩家与游戏世界交互的桥梁。Unity 的输入系统负责捕捉来自各种输入设备(如键盘、鼠标、手柄、触摸屏等)的信号,并将这些信号转化为游戏逻辑可以理解和响应的事件和数据。一个高效、灵活且易于使用的输入系统对于构建流畅、沉浸式的游戏体验至关重要。
本章节将深入探讨 Unity 的新输入系统 (Input System),这是 Unity 推荐的现代输入解决方案,它提供了比旧输入管理器 (Input Manager) 更强大、更灵活的功能。我们将从基本概念入手,逐步深入到高级用法,并通过代码示例和图表帮助您全面掌握 Unity 的输入系统。
Unity 新输入系统的核心围绕以下几个关键概念展开:
输入设备 (Input Devices):代表物理输入源,例如键盘、鼠标、游戏手柄、触摸屏等。Unity 输入系统能够自动检测和识别连接到计算机的各种输入设备。
输入操作 (Input Actions): 这是新输入系统的核心概念,它将具体的物理输入(例如按下键盘上的空格键)与游戏逻辑中的抽象动作(例如“跳跃”)解耦。您可以定义一组操作,例如 "移动"、"跳跃"、"射击"、"菜单导航" 等,而无需直接关心具体的输入设备和按键。
输入操作资源 (Input Action Assets): 用于组织和管理输入操作的容器。您可以创建多个操作资源,根据不同的游戏场景或角色配置不同的操作集合。操作资源可以方便地在编辑器中创建、编辑和保存。
输入绑定 (Input Bindings): 定义了输入操作与具体输入设备控件之间的映射关系。例如,您可以将 "跳跃" 操作绑定到键盘的空格键、游戏手柄的 A 按钮,甚至是触摸屏上的特定区域。一个操作可以有多个绑定,支持多种输入方式。
输入处理器 (Input Processors): 允许您在输入值传递给游戏逻辑之前对其进行修改和处理。例如,您可以使用处理器来平滑摇杆输入、反转鼠标 Y 轴、或者对输入值进行缩放。
输入交互 (Input Interactions): 定义了输入操作被触发的条件,例如 "按下"、"释放"、"长按"、"双击" 等。交互可以帮助您更精确地控制输入操作的触发时机。
为了更好地理解这些概念之间的关系,我们可以使用 Mermaid 图绘制一个简单的流程图:
图 3.2.1 输入系统核心流程
如图所示,输入设备产生的信号首先通过 输入绑定 映射到 输入操作。然后,输入处理器 对输入值进行处理,输入交互 决定操作何时触发,最终将处理后的输入数据传递给 游戏逻辑 进行响应。
从 Unity 2019.3 版本开始,新输入系统作为 Package Manager 中的一个包提供。如果您还没有安装或启用新输入系统,请按照以下步骤操作:
打开 Package Manager: 在 Unity 编辑器菜单栏中,选择 "Window" -> "Package Manager"。
搜索 Input System: 在 Package Manager 窗口中,搜索 "Input System"。
安装 Input System: 找到 "Input System" 包,点击 "Install" 按钮进行安装。
安装完成后,Unity 会提示您重启编辑器以启用新输入系统。点击 "Yes" 重启编辑器。
重要提示: 启用新输入系统后,旧的输入管理器 (Input Manager) 仍然可以使用,但建议您逐步迁移到新输入系统,因为它提供了更强大和灵活的功能。您可以在 "Project Settings" -> "Player" -> "Active Input Handling" 中选择 "Input System Package (New)" 来完全启用新输入系统,或者选择 "Both" 同时支持新旧输入系统。
输入操作资源 (Input Action Assets) 是管理输入操作的核心工具。您可以在 Unity 编辑器中轻松创建和编辑操作资源。
创建 Input Action Asset:
在 Project 窗口中,右键单击您想要存放操作资源的文件夹。
选择 "Create" -> "Input Actions"。
为新的操作资源命名,例如 "PlayerInputActions"。
双击创建的 "PlayerInputActions.inputactions" 文件,将打开 Input Actions 编辑器窗口。
Input Actions 编辑器界面详解:
Input Actions 编辑器窗口主要分为三个区域:
Action Maps (操作映射): 位于左侧,用于组织和分组输入操作。您可以创建多个操作映射,例如 "Player"、"UI"、"Menu" 等,以便根据不同的游戏状态或场景激活不同的操作集合。
Actions (操作): 位于中间,显示当前选定的操作映射中的所有操作。您可以添加、删除、编辑操作。
Properties (属性): 位于右侧,显示当前选定的操作或操作映射的详细属性,例如操作类型、绑定列表、处理器、交互等。
创建和编辑操作 (Actions):
选择 Action Map: 在左侧 "Action Maps" 区域选择您要添加操作的操作映射 (例如 "Player")。
添加新操作: 点击 "Actions" 区域的 "+" 按钮,添加一个新的操作。
命名操作: 为新操作命名,例如 "Move"、"Jump"、"Fire"。
设置操作类型 (Action Type): 在 "Properties" 区域的 "Action Type" 属性中,选择操作的类型:
Value: 用于表示连续变化的输入值,例如摇杆、鼠标移动。
Button: 用于表示按钮的按下和释放状态,例如键盘按键、游戏手柄按钮。
Pass Through: 直接传递输入设备的值,不做任何处理,适用于特殊情况。
Vector2: 用于表示二维向量输入,例如摇杆、方向键。
Vector3: 用于表示三维向量输入。
Axis: 用于表示一维轴输入。
None: 无类型操作,通常用于分组或占位符。
添加绑定 (Bindings): 点击操作下方的 "+" 按钮,添加新的绑定。您可以通过以下方式添加绑定:
Listen: 点击 "Listen" 按钮,然后按下您想要绑定的输入设备控件(例如键盘上的 "W" 键)。输入系统会自动识别并创建绑定。
Path: 手动输入或选择输入设备控件的路径。例如,<Keyboard>/w 表示键盘上的 "W" 键,<Gamepad>/leftStick 表示游戏手柄的左摇杆。
Control Scheme: 根据预定义的控制方案 (Control Scheme) 添加绑定。控制方案允许您为不同的设备类型 (例如 "Keyboard&Mouse"、"Gamepad") 定义不同的绑定集合。
示例:创建一个简单的 "PlayerInputActions" 操作资源
创建一个名为 "PlayerInputActions" 的 Input Action Asset。
创建一个名为 "Player" 的 Action Map (默认已存在)。
在 "Player" Action Map 下创建以下操作:
Move: Action Type: Vector2
Bindings:
<Keyboard>/w (Up)
<Keyboard>/s (Down)
<Keyboard>/a (Left)
<Keyboard>/d (Right)
<Gamepad>/leftStick
Jump: Action Type: Button
Bindings:
<Keyboard>/space
<Gamepad>/buttonSouth (通常是 A 按钮)
Fire: Action Type: Button
Bindings:
<Mouse>/leftButton
<Gamepad>/rightTrigger
创建完成后,您的 "PlayerInputActions" 操作资源应该类似于下图:
图 3.2.2 "PlayerInputActions" 操作资源示例
创建并配置好 Input Action Asset 后,您可以生成 C# 脚本来访问和使用这些输入操作。
生成 C# 脚本:
在 Input Actions 编辑器窗口中,切换到 "Properties" 区域。
展开 "Generate C# Class" 部分。
勾选 "Generate C# Class" 复选框。
设置 "Class Name" (例如 "PlayerInput") 和 "Namespace" (可选)。
点击 "Apply" 按钮。
Unity 将会在与 ".inputactions" 文件相同的目录下生成一个 C# 脚本 (例如 "PlayerInput.cs")。这个脚本包含了访问和使用您定义的操作的代码。
代码实践:使用生成的 C# 脚本读取输入
创建一个新的 C# 脚本 (例如 "PlayerController.cs"),并将其附加到一个 Unity 场景中的 GameObject 上 (例如创建一个空的 GameObject 并命名为 "PlayerController")。
在 "PlayerController.cs" 脚本中,编写以下代码:
using UnityEngine; using UnityEngine.InputSystem; public class PlayerController : MonoBehaviour { private PlayerInput playerInput; // 生成的 C# 脚本类 private Vector2 moveDirection; private void Awake() { playerInput = new PlayerInput(); // 创建 PlayerInput 实例 playerInput.Player.Enable(); // 启用 "Player" 操作映射 // 注册 "Move" 操作的回调函数 (Value 类型) playerInput.Player.Move.performed += context => moveDirection = context.ReadValue<Vector2>(); playerInput.Player.Move.canceled += context => moveDirection = Vector2.zero; // 输入取消时重置方向 // 注册 "Jump" 操作的回调函数 (Button 类型 - performed 表示按下) playerInput.Player.Jump.performed += context => Jump(); // 注册 "Fire" 操作的回调函数 (Button 类型 - started 表示按下,canceled 表示释放) playerInput.Player.Fire.started += context => FireStart(); playerInput.Player.Fire.canceled += context => FireEnd(); } private void Update() { // 使用 moveDirection 控制角色移动 (示例) Vector3 movement = new Vector3(moveDirection.x, 0f, moveDirection.y) * Time.deltaTime * 5f; transform.Translate(movement); } private void OnDisable() { playerInput.Player.Disable(); // 禁用 "Player" 操作映射 } private void Jump() { Debug.Log("Jump!"); // 在这里编写跳跃逻辑 } private void FireStart() { Debug.Log("Fire Start!"); // 在这里编写开火开始逻辑 (例如开始蓄力) } private void FireEnd() { Debug.Log("Fire End!"); // 在这里编写开火结束逻辑 (例如发射子弹) } }
代码详解:
using UnityEngine.InputSystem;: 导入新输入系统的命名空间。
private PlayerInput playerInput;: 声明一个 PlayerInput 类型的变量,PlayerInput 类是您生成的 C# 脚本类名。
playerInput = new PlayerInput();: 在 Awake() 方法中创建 PlayerInput 类的实例。
playerInput.Player.Enable();: 启用 "Player" 操作映射。只有启用的操作映射才会接收输入事件。
playerInput.Player.Move.performed += context => ...;: 注册 "Move" 操作的 performed 事件的回调函数。
performed: 当操作被触发时调用 (例如按下按键、移动摇杆)。
context: InputAction.CallbackContext 类型的参数,包含了输入事件的上下文信息,例如输入值、设备信息等。
context.ReadValue<Vector2>(): 从上下文中读取 "Move" 操作的 Vector2 类型的值。
playerInput.Player.Move.canceled += context => ...;: 注册 "Move" 操作的 canceled 事件的回调函数。
canceled: 当操作被取消时调用 (例如释放按键、摇杆回到中心位置)。playerInput.Player.Jump.performed += context => ...;: 注册 "Jump" 操作的 performed 事件的回调函数。由于 "Jump" 是 Button 类型,我们不需要读取值,只需要在 performed 事件中调用 Jump() 方法。
playerInput.Player.Fire.started += context => ...; 和 playerInput.Player.Fire.canceled += context => ...;: 注册 "Fire" 操作的 started 和 canceled 事件的回调函数。
started: Button 类型操作按下时触发。
canceled: Button 类型操作释放时触发。
transform.Translate(movement);: 在 Update() 方法中使用 moveDirection 来控制 GameObject 的移动 (示例代码,您可以根据实际需求修改移动逻辑)。
playerInput.Player.Disable();: 在 OnDisable() 方法中禁用 "Player" 操作映射,释放资源。
运行场景:
确保您创建了 "PlayerInputActions" 操作资源并生成了 C# 脚本 "PlayerInput.cs"。
创建一个空的 GameObject 并命名为 "PlayerController"。
将 "PlayerController.cs" 脚本附加到 "PlayerController" GameObject 上。
运行 Unity 场景。
现在,您可以使用键盘 WASD 键、空格键、鼠标左键,或者连接游戏手柄并使用左摇杆、A 按钮、右扳机来控制 "PlayerController" GameObject 并查看 Debug.Log 输出。
输入处理器 (Input Processors) 和交互 (Input Interactions) 是新输入系统的高级功能,可以帮助您更精细地控制和处理输入。
输入处理器 (Input Processors):
输入处理器允许您在输入值传递给游戏逻辑之前对其进行修改和处理。您可以在 Input Actions 编辑器中为每个绑定添加处理器。
常用的输入处理器包括:
Invert: 反转输入值。
Normalize: 将输入值归一化到 0 到 1 范围。
Clamp: 将输入值限制在指定范围内。
Scale: 缩放输入值。
Smooth: 平滑输入值,减少抖动。
Deadzone: 设置死区,忽略小于一定阈值的输入值 (常用于摇杆)。
示例:使用 Smooth 和 Deadzone 处理器
假设您想要平滑摇杆输入并设置死区,可以按照以下步骤操作:
在 Input Actions 编辑器中,选择 "Move" 操作的 Gamepad 左摇杆绑定。
在 "Properties" 区域的 "Processors" 部分,点击 "+" 按钮添加 "SmoothVector2" 处理器。
再次点击 "+" 按钮添加 "Deadzone" 处理器。
调整 "Smooth Time" 和 "Deadzone Min" 属性值。
输入交互 (Input Interactions):
输入交互定义了输入操作被触发的条件。您可以在 Input Actions 编辑器中为每个操作添加交互。
常用的输入交互包括:
Press: 默认交互,按下时触发 performed 事件,释放时触发 canceled 事件。
Hold: 长按交互,按下超过一定时间后触发 performed 事件,释放时触发 canceled 事件。
Tap: 点击交互,快速按下并释放时触发 performed 事件。
Multi Tap: 多次点击交互,在一定时间内点击多次时触发 performed 事件。
Slow Tap: 慢速点击交互,按下超过一定时间后释放时触发 performed 事件。
示例:使用 Hold 交互实现长按操作
假设您想要实现一个 "冲刺" 操作,需要长按 "Shift" 键才能触发,可以按照以下步骤操作:
在 Input Actions 编辑器中,创建一个名为 "Sprint" 的 Button 类型操作。
将 "Sprint" 操作绑定到 <Keyboard>/leftShift 键。
在 "Sprint" 操作的 "Interactions" 部分,点击 "+" 按钮添加 "Hold" 交互。
调整 "Duration" 属性值,设置长按时间 (例如 0.5 秒)。
在代码中,您可以监听 "Sprint" 操作的 performed 事件,在长按 "Shift" 键超过 0.5 秒后触发冲刺逻辑。
控制方案 (Control Schemes) 允许您为不同的设备类型 (例如 "Keyboard&Mouse"、"Gamepad"、"Touch") 定义不同的绑定集合。这使得您可以轻松地支持多种输入设备,并根据当前使用的设备自动切换控制方案。
创建控制方案:
在 Input Actions 编辑器窗口的左上角,点击 "Control Schemes" 区域的 "+" 按钮。
为新的控制方案命名,例如 "Keyboard&Mouse"、"Gamepad"。
在控制方案的 "Device Requirements" 部分,点击 "+" 按钮添加设备要求。
选择或手动输入设备类型路径,例如 <Keyboard>、<Mouse>、<Gamepad>。
为操作添加控制方案绑定:
在 Input Actions 编辑器中,选择一个操作 (例如 "Move")。
在 "Bindings" 区域,点击 "+" 按钮添加新的绑定。
在新绑定的 "Control Scheme" 属性中,选择您要绑定的控制方案 (例如 "Keyboard&Mouse" 或 "Gamepad")。
为该控制方案绑定设置具体的输入设备控件路径。
代码中获取当前控制方案:
您可以使用 InputUser.current.controlScheme 属性在代码中获取当前使用的控制方案名称。
示例:根据控制方案切换 UI 提示
using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; public class UI提示Controller : MonoBehaviour { public Text promptText; private void Update() { string currentControlScheme = InputUser.current.controlScheme; if (currentControlScheme == "Keyboard&Mouse") { promptText.text = "按空格键跳跃 (键盘鼠标)"; } else if (currentControlScheme == "Gamepad") { promptText.text = "按 A 按钮跳跃 (游戏手柄)"; } else { promptText.text = "请连接输入设备"; } } }
新输入系统还提供了对 Unity UI (uGUI) 的集成,允许您使用输入操作来控制 UI 元素。
设置 Event System 组件:
在您的 Canvas GameObject 上,确保有一个 Event System 组件。
在 Event System 组件的 "Input Module" 列表中,添加 "Input System UI Input Module" 组件,并移除默认的 "Standalone Input Module" 组件。
使用 Input Actions 控制 UI:
在 Input System UI Input Module 组件中,您可以配置 "Move"、"Submit"、"Cancel"、"Point"、"Click"、"ScrollWheel"、"MiddleClick"、"RightClick" 操作,将它们与您定义的输入操作绑定。
例如,您可以将 "UI_Navigate" 操作 (Vector2 类型) 绑定到 UI 的 "Move" 操作,使用摇杆或方向键控制 UI 元素的导航。将 "UI_Submit" 操作 (Button 类型) 绑定到 UI 的 "Submit" 操作,使用空格键或 A 按钮选择 UI 元素。
代码中控制 UI 导航:
您可以使用 UnityEngine.EventSystems.EventSystem.current.SetSelectedGameObject() 方法在代码中控制 UI 元素的选中状态,并结合输入操作来实现更复杂的 UI 交互逻辑。
自定义输入处理器和交互: 您可以创建自定义的输入处理器和交互来满足特定的输入处理需求。
性能优化: 合理组织输入操作和绑定,避免不必要的事件处理,可以提高输入系统的性能。
输入调试: 使用 Input Debugger 窗口 (Window -> Analysis -> Input Debugger) 可以实时查看输入设备状态、操作状态、事件信息,帮助您调试输入问题。
版本控制: 将 Input Action Assets 文件纳入版本控制系统,方便团队协作和版本管理。
代码组织: 将输入相关的代码逻辑封装到专门的脚本或模块中,提高代码可维护性。
Unity 新输入系统是一个强大而灵活的输入解决方案,它通过 输入操作 (Input Actions) 的概念解耦了物理输入和游戏逻辑,提供了更清晰、更可维护的输入管理方式。掌握输入系统的核心概念、操作资源、绑定、处理器、交互、控制方案等功能,将使您能够构建更丰富、更流畅、更易于扩展的游戏输入体验。
本章节介绍了 Unity 输入系统的基本概念和常用功能,并通过代码示例和图表帮助您入门。建议您深入实践,探索更多高级用法,并根据您的项目需求灵活运用输入系统,打造出色的游戏操控体验。
希望本章节内容对您有所帮助!