直接使用
通过Package Manager安装好InputSystem之后可以同时导入一些范例资源,阅读其使用代码,InputSystem有几种不同的使用方法,开发时应按需求酌情选择。
需要注意的是,安装好InputSystem之后会有提示询问是否切换到新版输入管理系统,切换后Input Setting面板将失效,游戏中也无法使用Input类获取输入。
此外还有一点,默认的UI事件监听组件StandaloneInputModule无法处理InputSystem的输入,选中EvenSystem之后可以在Inspector中将其替换为InputSystemUIInputModule组件。
直接使用InputSystem的方法很简单,系统提供了各种设备对应的管理类和当前实例
Gamepad gamepad = GamePad.current; // 手柄 Joystick joystick = Joystick.current; // 摇杆 Keyboard keyboard = Keyboard.current; // 键盘 Pointer pointer = Pointer.current; // 指针,屏幕上的指定位置操作,包括鼠标,触屏以及手写笔等子类 Mouse mouse = Mouse.current; // 鼠标 Touchscreen touch = Touchscreen.current; // 触屏 Pen pen = Pen.current; // 手写笔 Sensor sensor; // 传感器基类,由它派生出包括加速度,温度,重力,陀螺仪等在内的一系列传感器,均有各自对应的类 // 手柄输入获取范例 Vector2 leftAxis = gamepad.leftStick.ReadValue(); float leftTriggerValue = gamepade.leftTrigger.ReadValue(); bool aButtonDown = gamepad.aButton.wasPressedThisFrame; bool aButtonPress = gamepad.aButton.isPressed; bool aButtonUp = gamepad.aButton.wasReleasedThisFrame; // 鼠标输入获取范例 Vector2 mousePosition = mouse.position.ReadValue(); Vector2 moveDelta = mouse.delta.ReadValue(); bool leftButtonDown = mouse.leftButton.wasPressedThisFrame; bool leftButtonPress = mouse.leftButton.isPressed; bool leftButtonUp = mouse.wasReleasedThisFrame; // 键盘输入获取范例 bool anyKeyDown = keyboard.anyKey.wasPressedThisFrame; bool anyKeyPress = keyboard.anyKey.isPressed; bool anyKeyUp = keyboard.anyKey.wasReleasedThisFrame;
新版InputSystem对大部分常用的输入设备都定义了详细的控制类,其中具体的控制项则基于InputControl基类派生出的各种处理类,包括但不仅限于AxisControl,ButtonControl,TouchControl等。
如果考虑多个同类型的输入设备,比如多个手柄或者多个键盘,那么应使用InputSystem.devices列表来获取所有可用设备并从中找到自己所需的那个。
使用ActionAsset映射表
ActionAsset资源是新版InputSystem用于映射物理设备的具体操作项与游戏行为的工具,它的作用类似旧版InputSetting中将某几个具体输入项绑定到名称上并使用名称获取输入的用法,但具体操作有较大区别。
要使用ActionAsset首先要在Assets文件中创建资源,右键Create,然后选择InputActions,进行命名后即可创建出一个空的ActionAsset。
双击打开新创建的资源文件即可开启一个新窗口,用于编辑所有的输入映射,窗口内容分三列,最左侧的ActionMaps是最顶层的映射表显示区,这里会展示当前资源中包含的所有映射表。
一个资源可以包含多个映射表,这其实就是用于在游戏中方便地切换不同的操作逻辑,比如说人物在正常状态和载具中时分别有不同的操作方法,同一个按钮会有不同的功能,使用ActionMap可以很方便地配置这些操作方法并在游戏中动态切换。
窗口中间是Actions列表,表示当前ActionMap下所有可用的动作,这个表和旧版InputSetting的列表十分相似,添加一个Action并给它命名,随后通过右侧加号或者邮件点击来添加绑定。
相比于旧版InputSetting,Action的绑定选项要丰富得多,首先Action自身可以规定一个动作类型,Value,Button,PassThrough三选一。
其中Value指代各种连续变化的输入,比如鼠标移动,摇杆偏移,手柄扳机等,但这个选项只会获取当前受控制的一个设备输入。
Button则表示按钮输入,无论是鼠标按钮或是手柄按钮,其输入结果为布尔型。
PassThrough和Value基本相同,但它可以获取所有可用输入设备的输入。
其次,Action自身也可以给定一套交互规则,即Interactions选项,每个交互规则的具体定义可以查询官方文档,以Hold规则为例,添加该规则后会有两个数值设定,分别是Press Point和Hold Time。
其中Press Point表示指定按钮的按下幅度阈值,换言之要按下到多少才认定该按钮处于“按下”状态,通常而言采用默认值即可。
而Hold Time就是Hold规则的主角了,它表示指定按钮被按下并保持一段时间后认为其满足规则,予以触发,在实际使用中则是当按钮被按下时会触发started回调,按下时间超过Hold Time之后则触发performed回调,否则触发canceled回调。
由此可以看出,Interactions规则的设定可以在一定程度上替代游戏本体逻辑中编写各种特殊操作的流程,比如常用的长按,单击,多次点击等等。
Action还能为自身定义预处理器,即Processors一栏,它包含Deadzone,Clamp,Invert,Normalize和Scale五种预处理器,它们各自的作用和用法可查看文档。
以Deadzone为例,这个预处理器可以配置输入值的有效区间,不在区间内的输入被认定为无效,可用于解决摇杆过于灵敏的问题。
添加绑定之后,每个单独的绑定项可以设置自己的绑定路径,这部分的设置会稍显复杂,因为可用的物理路径多种多样,也包括各种自定义的输入设备,需参考官方文档妥善配置。
单个绑定也可以添加Interactions和Processors来制定输入规则和预处理数值,相比于Action对所有绑定项的输入进行规范和处理,这里的配置将只对特定的绑定项起作用,可以用于规范某些特殊设备的输入。
配置好ActionMap之后便可以使用这项资源来定义用户的输入了。
PlayerInput组件
该组件是新版InputSystem中包含的玩家输入组件,它需要和ActionAsset资源配合使用,挂载到操作对象上之后,将ActionAsset设置到Actions项上并为它选择默认的ActionMap即可将两者连接。
随后注意到Behavior选项,其下有四个选项,分别是SendMessage,BroadcastMessage,InvokeUnityEvent和InvokeCSharpEvent。
前两个选项很好理解,选中后也会看到说明,它们分别会向自身GameObject或者全局发送广播告知包括设备连接和断开在内的一系列事件。
第三项则需要在面板上配置每个事件的回调方法,也就是一般的UnityAction用法,可以方便地将脚本方法和Actions一一映射起来。
第四项则稍显复杂,它不能在面板上配置,必须在脚本中获取到PlayerInput组件后依次配置每个事件的回调方法,但这样会相对更灵活可控。
UIInputModule的设置是针对UI操作的,通常来说这个Module挂载在EventSystem对象上。
而Camera设置文档中写明是针对分屏游戏中将不同摄像机绑定给不同角色时使用的,一般情况下可以不考虑。
总结下来,PlayerInput组件的特点是使用方便,只需要进行一系列配置后便可使用,无需在代码中过多关心输入设备的情况以及具体输入值的获取,开发迅速且移植方便。
缺点同样明显,设置过程复杂,需要学习和迁移成本,除非使用广播,否则每个需要接受输入的对象都必须挂载组件。
直接使用ActionAsset资源
如果不喜欢PlayerInput组件,但依然想使用ActionAsset资源的话也是可以的,在此前创建好的ActionAsset资源的检视面板里勾选上Generate C# Class,选择路径,设置类名和命名空间后点击Apply即可自动生成一个脚本文件。
该脚本文件中包含了ActionAsset资源的所有信息并为其每一个ActionMap都配置了相应的接口和Wrapper类,这也就表示开发者可以在代码中直接引用该类而无需理会ActionAsset资源,也就用不着PlayerInput组件了。
具体代码如下
// 如果生成类的命名为MyControls MyControls ctrl = new MyControls(); // 如果ActionAsset中配置了一个名为TestMap的ActionMap MyControls.TestMapActions actMap = ctrl.TestMap; // 如果存在一个名为TestButton的Action绑定 InputAction testAct = actMap.TestButton; // 此时便可以为该Action添加各种回调 testAct.started += ...; testAct.performed += ...; testAct.canceled += ...;
需要注意的是,此处绑定的回调规则将和ActionAsset资源中的配置保持一致,也会受到Interactions和Processors的影响。
单独使用InputAction
如果连生成类都不想用,那么也可以直接在面板上配置InputAction,在脚本中定义InputAction类型的公开字段后便可在面板上看到设置项,其设置过程和ActionAsset资源编辑窗口中对单个绑定的编辑相同,同样可以为单个InputAction配置多个绑定,可以为InputAction设置Interactions和Processors,对绑定项也一样。
总结
新版InputSystem确实极大地拓展了Unity输入系统的可用性和普适性,但同时它引入和许多复杂的配置流程和概念,将原来一些简单而直接的输入方式变得繁杂,孰好孰坏只能交由实际项目来验证。
不过从学习以及个人开发的角度来看,新版InputSystem还是很有可取之处的,不光是它的功能丰富以及输入映射的开发理念,更重要的是——
这东西免费不是吗?(笑)
注释写得不错