首页 两轮车 三轮车 汽车 头条 报价 推荐 资讯 焦点 品牌 技术
首页 >  焦点 > 

时讯:Unity InputSystem使用教程

2023-04-09 16:56:10 来源:哔哩哔哩

前言:

本篇主要为大家讲解InputSystem输入系统的基础使用方式以及各选项的功能。

如果您对老版输入系统有过使用经验,那么上手将会非常的顺畅。如果您是刚开始学习Unity的新同学也没有关系,本篇会从基础开始讲述,每一个步骤都尽可能配有操作截图和代码,看完相信您也能轻松学会。


【资料图】

想要使用InputSystem,建议使用Unity 2019.x及以后的版本,因为2018版本的InputSystem还是一个preview版本。本着听人劝吃饱饭的优良传统,作者果断选择了新版本。

我这里采用的是Unity 2021版。

准备工作

第一步我们需要安装InputSystem。

在菜单栏中选择“Window→Package Manager”在弹出的 Package Manager面板中选中“Input System”,单击右下角的Install安装,如果列表中显示的内容较少并找不到Input System时,可以将窗口顶部的“Packages”切换为“Unity Registry”即可。

安装后选择“Yes”,会重启Unity,重启后安装完毕。

安装结束后,我们在顶部菜单栏选择“Edit→Project Settings”点击“Player”我们可以看到Active Input Handling已经切换为“Both”,

这个地方有三个选项:

Input Manger(Old):只采用旧版的Input输入,新版的Input System将不起作用。

Input System Package(New):只采用新版的Input System方式,旧版的Input将不再起作用。

Both:两种方式同时起作用

我们选用“Input System Package(New)”或者“Both”都可以。

Input System的使用方式大致分为两种,一种是通过InputSysten Package提供的组件,在编辑器通过拖拽,选择,挂载等方式,进行函数与输入动作的绑定;另一种是使用代码对函数与输入动作进行绑定。

本文主要侧重于在代码中如何使用Input System,对于编辑器组件面板就适当省略或者开一篇新文章专门讲解。

常用功能对比

安装完毕后我们来对比一下,新老版本的使用差别,下面提供一个官方的文档连接,如果有需要可以查看https://docs.unity3d.com/Packages/com.unity.inputsystem@1.1/manual/Migration.html#unityengineinputanykeydownhttpsdocsunity3dcomscriptreferenceinput-anykeydownhtml

新旧版的键盘按键监听对比:

以监听"A"键按下,抬起,按住为例

旧版:Input.GetKeyDown(KeyCode.A);

Input.GetKeyUp(KeyCode.A);

Input.GetKey(KeyCode.A);

新版:Keyboard.current.aKey.wasPressedThisFrame;

Keyboard.current.anyKey.wasReleasedThisFrame;

Keyboard.current.anyKey.isPressed;

其余键盘按键与“A”并无差别,将“aKey”更换为“bKey”、“cKey”......即可

新旧版的鼠标左键监听对比:

旧版:Input.GetMouseButtonDown(0);

Input.GetMouseButtonUp(0);

Input.GetMouseButton(0);

新版:Mouse.current.leftButton.wasPressedThisFrame;

Mouse.current.leftButton.wasReleasedThisFrame;

Mouse.current.leftButton.isPressed;

鼠标中键、右键使用方法并无差别,将“leftButton”更换为“middleButton”/“rightButton”。

这里的isPressed要稍微提一下,我们按住Ctrl点击isPressed会发现,按住的判断是通过ReadValue()与一个默认值pressPointOrDefault进行对比返回的结果。所以也可以用

Keyboard.current.aKey.ReadValue()>=N

自己指定一个数值N来进行判断,一般来说按下与抬起只会返回0/1,考虑到浮点数的精度问题,建议不要直接使用0或者1来进行判断,避免出现一些精度问题。关于这个地方我们在后边InputActions部分还会做讲解,这个地方就不再说了。

最后就是鼠标位置和滚轮的数据获取。

鼠标位置对比

旧版:Input.mousePosition;

新版:Mouse.current.position;

滚轮对比

旧版: Input.GetAxis("Mouse ScrollWheel");

新版:Mouse.current.scroll.ReadValue();

滚轮这个地方要稍微注意一点,旧版的会直接返回一个float的值,而新版本则会返回Vector2,如果想返回float请使用Mouse.current.scroll.ReadValue().y,值得注意的是,新版返回的Y值一般都较大,我这边根据滚动的速度不同大概都在0,120,240,360左右,希望各位有所了解。

更多的使用区别请参考一开始给出的官方文档,这里就不再一一列举了。

Input Actions

Input Actions是新版输入系统的重点!此处篇幅较长并且与编辑器面板操作较多。

新建Input Actions:

方法一:在Project面板下右键单击,在弹出的菜单中找到“Input Actions”,修改新建“Input Actions”的名称。

方法二:在顶部菜单栏选择“Assets-Create-Input Actions”

选中新建的Input Actions,将"Generate C# Class"勾选,这样可以为我们生成代码,后续要是用,很重要。

其余三个选项

C# Class File:生成的C#代码存放位置。默认与Input Actions同级

C# Class Name:生成C#代码的类名。默认与Input Actions同名

C# Class Namespace:生成代码所处的命名空间。

修改完以后点击Apply保存。

双击新建的Input Actions或者在Inspector面板选择Edit asset,打开Input Actions编辑面板,在此面板我们可以创建一些自己的行为。

点击Action Maps旁边的“+”创建一个“行为映射表”,新建的Map下会带有一个空action和一个未绑定Control的Binding。下边会解释。

现在我们细说一下上述步骤出现的几个概念以及Input Actions配置界面的一些选项。

InputAction Assets,输入行为资产,可以理解成自定义的输入行为(动作)的集合。一个输入动作可以由一种或者多种输入信号组成。比如“前进”这个动作,可以被“W”键触发,也可以被“↑”方向键触发,甚至可以被手柄的“↑”键触发。

Action Map:行为映射表,一个Input Actions可以有多个Map。每个Map下面又有许多Action,可以批量控制Action启用与禁用。比如有一个UI Map,他包含选项的上,下,左,右,确定等功能,我们将这些功能绑定在方向键。另一个Car Map,他控制赛车的移动,绑定的同样是方向键。为了避免功能冲突,我们可以再拉起UI面板的时候,整体禁用Car Map,关闭UI面的时候禁用UI Map,启用Car Map。以及其他类似的操作。

Input System将动作分为三种类型

Button:按钮类型,相对简单只处理按下与抬起,并返回对应数值,可以看做离散型非0  即1。使用ReadValue<float>() 来获取会获得0/1。

Value:值类型,与Button相比,它可以返回连续的数值,比如接入手柄以后,摇杆可以    返回范围内的任何值。返回值的类型可以在Control Type中设置,下方会详细说明。

PassT hrough:直通类型,与Value几乎一致,但是它可以返回所有设备的输入,而Value只会返回当前最优先的设备输入。

Control Type:设置按键返回值的类型。之后会根据当前选择内容筛选输入设备。

Any:任何值                Axis:一维轴浮点数                Bone:骨骼

Digital:数字                  Dpad:手柄四向按钮              Eyes:VR相关数值

Integer:整数                 Quaternion:四元数               Stick:摇杆

Touch:触控屏               Vector2:二维向量                 Vector3:三维向量

Button:按钮

Initial State Check:启用 Action时,Action绑定的Control可能已经具有非默认状态,系统依次检查所有被绑定到此Action的Control,并立即响应处于非默认状态下的控件。

补充:输入系统将不同种类的输入抽象为Control。Control表示输入值的来源,例如,某个float值来源于键盘上的某个按键,某个Vector2值来源于鼠标单帧的位移,某个Vector2值来源于手柄上的摇杆。

参考自:https://blog.csdn.net/qq_39915907/article/details/125630907  本文部分参考自这篇文章,后续将不再写明,建议阅读。

Interactions:交互方式,可以理解为这个动作的触发方式,比如:点击,长按,双击等。

所有的方式都会默认有三个事件Started、Performed、Canceled。

举一个明显的例子,长按(手指按住1秒以上认为是长按):在按下去的瞬间触发Started,在任意时间松开触发Canceled,如果连续按压时间达到1秒触发Performed。

Hold:长按,需要保持按压一段时间才算完成这个动作。就像上方举得例子。

Press Point:表示一个临界点,只有过了这个值才算按下。如果Button则只有0和1。如果是摇杆类的按钮,则需要推动幅度大于PressPoint才行。

Hold Time:长按时间,按下时间达到Hold Time后会立刻触发Performed。

Default如果勾选则会采用Unity提供的默认值,如果想要自定时间和临界值,请取消勾选。    

Open Input Settings:默认值可以点击Open Input Settings进行查看并修改,也可以“Edit→Project Settings→Input System Package”打开查看并修改。这两项后续不再讲述。

Multi Tap:连击,在规定时间间隔内点击指定的次数。

Tap Count:连击次数。

Max Tap Spacing:两次点击之间的时间间隔。

Max Tap Duration:单次点击 按下与抬起之间的最大持续时间。

只有每次点击都满足上述两个条件,才会触发Performed。

Press:类似按钮,

Press Only:在按下的时候触发Started和 Performed,在抬起的时候触发Canceled。              Release Only:在按下的时候Started,在抬起的时候触发Canceled和Performed。

Press And Release:在按下的时候触发Started和 Performed,抬起的时候触发Canceled和Performed。

Slow Tap:缓慢点击,他与Hold的区别是,在达到最短按压时间后不会立刻触发Performed,而是在松开的瞬间触发Performed。

Min Tap Duration按压的最短时间。

Tap:单击。可以看做只点击一次的Multi Tap。选项在Multi Tap中也有讲述

Processors:输入值处理,对返回的Value作出指定处理,如取反,限定范围等等。这个地方会因为上边选择的Control Type不同从而导致出现的选项也不同。部分功能类似的选项就会合并讲解。

Clamp:将输入值限制在[min,max]之间,值类型为Float。

Invert:将输入值取反(乘以-1)。应用场景,如果某方向控制键,左输入1右输入-1,我们日常的坐标系都是左为负数,右为正数,为了符合习惯可以取反。

Invert Vector2:同上。可以单独选择取反哪个轴。

Invert Vector3:同上。略。

Normalize:如果最小值>=0,则将[min,max]范围内的输入值规格化为无符号规格化形式[0,1],如果最小值<0,则将输入值规格化为有符号规格化形式[-1,1]。

Normalize Vector2:将输入值归一化,模长为1。比如使用摇杆控制人物移动时,我们往右前方移动,如果值为(1,1)那么就会比单纯前进(1,0)速度要快。这不是我们想要的,所以就要将输入值的模长限制为1。设置后可能会返回(0.71,0.71)其他角度类似。

Normalize Vector3:同上。

Scale:输入值乘以Factor

Scale Vector2:将X轴与x相乘,Y轴与y相乘。

Scale Vector3:类似同上。

Stick Deadzone:摇杆死区处理。摇杆或者其他设备可能存在轻微误触或者其他原因造成的信号问题,在边缘地区不准确。比如将摇杆右滑到底切换下一页,因为某些原因输入值永远在0.99f等等情况。所以只要小于Min值的信号都将变为0,大于Max值的信号都将变为1。

Axis Deadzone:axis死区处理。绝对值小于最小值的任何值为 0,绝对值大于最大值的任何值为 1 或 -1。

选中当前未绑定的<No Binding>,在右侧面板会有BindingInteractions、Processors三个选项。

其中Interactions和Processor是针对当前Binding的特别设置,与Action功能一致。如果此处未进行设置,就使用上级的Interactions/Processor设置;如果进行了设置,以此处Interactions/Processor的设置为准。

Binding是此处的核心,它的作用是用来对输入信号进行绑定。输入系统将Action与Control之间的连接抽象为Binding。Binding包含一条指向Control的控件路径,多个Binding可以指向同一个Control,一个Action可包含多个Binding。系统收到某个控件输入的数据时,会驱动所有绑定了该控件的Action进行响应。

Binding绑定

在Action Maps栏单击“+”新建Map后,双击新建的Map可以修改其名称“Player”,在Actions栏双击新建的Action修改名称“Jump”,选中<No Binding>,点击右侧的Path旁边的下拉菜单。

比如我们想用键盘“空格”触发跳跃,绑定的方法有三种:

方法1:选择“Keyboard”-"By location of key"-"Space",即可绑定。

方法2:在搜索框中直接搜索目标“Space”,点击即可绑定

关于每个按钮对应的选项以及外接手柄的对应,我会在后续的"Input Debugger"中讲述。

方法3(推荐):通过Listen绑定,点击Listen后就会开始监听输入,我们敲击“空格”,就会现在是在面板中,只要点击即可绑定。

这就是绑定的三种方法。

在实际情况中一个动作可能会被多个按键触发,继续用Jump举例子,在部分小游戏中跳跃可以被“空格”,“↑”甚至数字区的“8”来触发,对于这种情况,InputSystem给我们提供了一个非常简单的解决办法。

单机Jump旁边的“+”,选择“Add Binding”,会在Jump下添加一个新的Binding,我们只需要仿照上面的方法,挨个进行绑定,就可以让多个按钮触发同一个Action.

接下来我们来一起看看Action下的几个绑定选项

Add Binding:普通的绑定,可以绑定一个信号。

Add Positive\Negative Binding:由两个信号组成的绑定,返回一维向量。比如2d游戏中的左移/右移动。

选中“Negative ”与“Positive”后续绑定方法与Binding一致,此处的几个选项

Composite Type:没有查到相关资料,如果选择后两项会变成“Add Binging With One Modifier”和“Add Binding With Tow Modifiers”样式,此处不再展开讲解,如果有读者了解可以在评论区帮忙完善,感谢。

Min Value:Negative 绑定键的值

Max Value:Positive 绑定键的值

Which Side Wins:当同时按下两个键的处理方式,Neither,两个键都停止输入,Negative 和Positive返回指定输入值。

Add Up\Down\Left\Right Composite:返回二维数据,由四个信号组成,可以用于WASD,↑↓←→等。绑定与Binding一样。

Add Up\Down\Left\Right\Forward\Backward Composite:返回三维数据,由六个信号组成,类似Unity的WASDQE,控制前后左右上下等。绑定与Binding一样。

Add Binging With One Modifier:组合键,例如Ctrl+S,Ctrl+Z等

Add Binding With Tow Modifiers:组合键,例如组合键Ctrl+K+C,Ctrl+K+U等等

在使用组合键的时候,注意热键冲突。类似“Alt+F4”这样的组合键,只能说劝君慎重!!!

Input Debug

Input Debug窗口是一个非常好用的东西,打开方式:

“Window→Analysis→Input Debugger”

这个窗口中,所有可以被识别的输入设备都会被显示在这。之前我们在绑定输入按钮的时候会不会有这么一个疑惑,我怎么知道这个按钮对应哪个信号。还有每个信号的输入值类型又是什么样子呢?

我们就以我的手柄为例,上图中我已经选中了手柄,双击,打开详细界面。

我们可以看到设备的详细信息。Name就是在Unity InputSystem中对应的名称;DisplayName是我手柄上的文字,B就对应我手柄的B;后边还有信号类型方便我们设置Type。此时按动手柄还能通过value看到实时输入值,并且屏幕下方还会实时打印,方便我们调试。爆赞!

比如我此时正在按B键,掰动摇杆,所有的输入信息都会在面板中展示出来,建议各位自己尝试一下。

Input Actions配置界面的内容大部分就已经讲完了还有一个ControlSchemes,这部分我们等到接入手柄以后再讲解。下面我们正式在代码中使用我们自定的Input Actions。

对我来说,使用代码更加直观,也更易于理解一点。

先来看一下我的Input Actions是长什么样子的。以免下面代码中出现一些名字让人产生疑惑。

我的InputActions我改名为“MyInputSystem”,他有一个Map名字是“Player”,下面有两个行为“Jump”跳跃绑定的是键盘的空格键,“Movement”移动绑定的是WASD。

点击上方的"Save Asset",保存我们的设置,并且生成对应的代码。代码保存路径就在我们一开始提过的,如果遗忘,请向上翻找。

为了保持各位的阅读连贯性,就不分上下篇。

直接二合一!

使用Input System,我们的脚本需要引用using UnityEngine.InputSystem

生成的代码各位可以自行查看,这里就不详讲,要不然篇幅太长了。

新建一个脚本。引入命名空间。

声明自定义的InputActions并实例化,我这边的类名是MyInputSystem。

注意:使用之前一定要执行Enable();否则不起作用。每一个Map以及Action都可以单独设置Enable和Disable;

现在输入监听就已经开启了。

我们让跳跃函数与Jump绑定。

绑定Movement

使用ReadValue<T>()来获取数值,这个T尽可能与在面板中设置的Control Type保持一致,以免发生一些预料之外的错误。

上面讲过,每个Action默认有started,performed,canceled事件。所以我们扩展成以下形式。

您可以尝试将自己的定义的Action与函数进行绑定。这种写法,会在监听到绑定的信号输入时调用对应事件。属于按一下执行一次,不会一直回调。

目前可能并不太能直观的体现出三种事件的区别。

我们现在把Jump改一下,变成performed要蓄力1秒才会触发。这样大家就能看出来明显的区别。修改完以后记得保存。

inputActions.Player.Jump.started += ctx=>Debug.Log("按下空格");

inputActions.Player.Jump.performed += ctx => Debug.Log("蓄力完成");

inputActions.Player.Jump.canceled += ctx => Debug.Log("松开空格");

38秒按下空格触发started ,1秒(39秒)后触发performed ,40秒抬起空格触发canceled 。

可以看到,现在三个事件已经出现了明显的区别。

这个地方大家一定要自己多多实践,与上半部分那些设置组合起来多多尝试,才能更好的使用。我这篇文章也不能给大家把所有的组合全部展示出来,那样也没有意义。

接入手柄

在开发中,移动并不是单纯靠键盘输入,可能还有靠手柄,现在很多手柄配有摇杆,输入的值也并不是非0即1,这样可以通过摇杆控制角色移动的同时并控制速度。

我们继续在Movement下添加手柄摇杆。此处要将Mode改成Analog,否则还是会和按键一样,只能返回0/1。下方的Processors进行归一化设置,上边讲过是为了限制模长为1。

接入代码看看最后的效果。

private void Update()

{

//因为要每帧都获取数据,所以需要在Update中

if (inputActions.Player.Movement.IsPressed())

{

Debug.Log(inputActions.Player.Movement.ReadValue<Vector2>());

}

}

现在已经可以看到,摇杆已经被成功接入,并且可以获取摇杆推动的幅度。

手柄的其他按键与摇杆也可以通过类似的方法进行设置。

补充——手柄震动

对于部分支持震动的手柄来说,我们可以用代码控制它震动。方式获取要震动的手柄,设置最低震动频率与最高震动频率。上代码!

注意,实际应用时应该增加一步判空检查,避免报错。

private void OnEnable()

{

//手柄可以直接指定当前手柄,也可以通过InputAction.CallbackContext回调获取

//开启震动.

Gamepad.current.SetMotorSpeeds(0.2f, 0.5f);

}

private void OnDisable()

{

//结束震动

Gamepad.current.SetMotorSpeeds(0, 0);

}

Control Scheme——控制方案

随着我们接入手柄,我们现在已经有了键盘,手柄两套输入,随着以后项目的完善可能还会接入其他外设,比如方向盘模拟器,某专用手柄等等。定义的行为也会越来越多,显示的内容可能会很多,Control Scheme 可以帮我们更好的管理定义的行为,方便切换平台等。

点击左上角菜单 → AddControl Scheme 

Add Control Scheme:添加一个方案。

Edit Control Scheme  :编辑一个方案。

Duplicate Control Scheme :复制一个方案。

Delete Control Scheme :删除一个方案。

Requirements: 列表中的每种类型设备可以选择为Optional或Required

Optional: 可选的(官方未给出说明)

Required: 必要的(官方未给出说明)

这里我们新建一个“Player”和“Gamepad”

现在每一个binding都会出现选“Use in control Scheme”选项。勾选相应的选项。

Control Schemes可以进行过滤显示,点击上方选项,选择一个Control Scheme或者All Control Schemes全部显示。

点击后边的Device,可以通过Device进行过滤显示。

删除Control Schemes的时候要注意,切换到自定义Schemes,选择删除后, 首先会询问是否确定删除。选择确定后会弹出,是否删除所有勾选为指定Schemes的Binding,以当前为项目例,如果选择“yes”,所有勾选"Player"的Binding都会被删除,如果选择“No”则Binding会被保留只删除Control Schemes。

补充:使用inputSystem后,UI的EventSystem根据选择模式不同可能会失效。使用UI前请点击“Replace with InputSystemUIInputModule”。

到这里InputSystem的基础使用方法基本就介绍完毕。

到这篇幅也已经不短了再接着写下去也不合适。 还有一些其他内容在这里就不展开讲解,比如Input System支持输入记录,多手柄等等,还有一些选项的具体使用方法,以及Player Input的使用,编辑器上点击配置一些函数的调用等等。

如果有较多的人想看或者需要这方面的演示,我可以专门出一期视频来展示,那些内容用文章的方式不是非常合适,也不直观。

如果本文对您有所帮助,请支持一下作者。

求赞,求赞,求赞

我们下期再见

关键词:

下一篇:
上一篇:

相关新闻