Unity的输入系统支持多种输入设备,比如键盘和鼠标,游戏手柄,触摸屏,VR和AR控制器等等。Unity 通过两个独立的系统提供输入支持:第一,输入管理器 (Input Manager) 是 Unity 核心平台的一部分,默认情况下可用,属于旧的unity输入系统。第二,输入系统 (Input System) 是一个包,必须先通过 Package Manager 进行安装后才能使用,属于新的unity输入系统。当然,我们本课程仍然还是从旧的输入系统Input Manager开始讲解。
由于输入基本上都是在脚本中处理的,因此有关输入处理的代码逻辑都是在Update方法中实现。这里就需要介绍Unity提供的Input类,该类提供了很多的静态变量和静态方法用于输入信息的获取。其实,在我们之前的章节案例中,我们也使用过该类获取键盘输入,例如:Input.GetKey(KeyCode.A) 就用来判断用户是否按下了字母 A 键,也就是说,GetKey方法是用来获取键盘输入的,其参数就是键盘的键值,并且这些键值也都是Unity已经提供好的常量值。接下来,我们就来看看Input类到底给我们提供了那些变量和方法。
首先,我们先看看它里面的静态变量。
anyKey 当前是否有任何键或鼠标按钮处于按下状态。
anyKeyDown 在用户按任意键或鼠标按钮后的第一帧返回 true。
inputString 返回该帧输入的键盘输入。
location 用于访问设备位置的属性(仅限手持设备)。
mousePosition 鼠标当前的像素坐标位置。
我们只是简单介绍几个,我们重点介绍Input类的静态方法
GetKey 在用户按下 name 标识的键时返回 true。
GetKeyDown 在用户开始按下 name 标识的键的帧期间返回 true。
GetKeyUp 在用户释放 name 标识的键的帧期间返回 true。
以上三个方法主要用于键盘按键的获取。接下来,我们就使用代码来演示。我们创建一个新的“InputManagerDemo”工程,然后在默认的场景中创建“InputScript.cs”脚本文件,如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InputScript : MonoBehaviour
{
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.A))
{
Debug.Log("键值A");
}
if (Input.GetKeyDown(KeyCode.A))
{
Debug.Log("按下键值A");
}
if (Input.GetKeyUp(KeyCode.A))
{
Debug.Log("按上键值A");
}
}
}
然后我们将脚本附加到相机“Main Camera”上,然后运行工程,按下键值A进行测试。
在控制台,我们启用了折叠功能,就是将相同的日志一行显示,而后面的数字则是相同日志重复输出的次数。我们可以发现,当我们按下一次键值A的时候,GetKeyUp 和 GetKeyDown只会触发一次,而 GetKey 方法则会根据用户按下的时间长短触发多次。关于键值常量,我们也可以简单的说明一下,毕竟一个键盘的常用按键也并不多。
KeyCode.A – KeyCode.Z 代表26个因为字母,这个就不详细介绍了。
KeyCode.Alpha0 - KeyCode.Alpha9 代表主键盘上的数字键。
KeyCode.Keypad0 - KeyCode.Keypad9 代表小键盘上的数字键。
KeyCode.F1 - KeyCode.F12 代表F1-F12的功能键。
Backspace = 退格键;Delete = 删除键;Tab = 缩格键;Escape = 退出键;Space = 空格键;Return = 回车键;RightShift = 右shift键;LeftShift = 左shift键;RightControl = 右Ctrl键;LeftControl = 左Ctrl键;RightAlt = 右Alt键;LeftAlt = 左Alt键;UpArrow = 向上箭头键;DownArrow = 向下箭头键;RightArrow = 向右箭头键;LeftArrow = 向左箭头键。
关于这些键值,我们不需要刻意的记忆,在日常开发中,使用多了自然就记住了。
GetMouseButton 返回是否按下了给定的鼠标按钮。
GetMouseButtonDown 在用户按下给定鼠标按钮的帧期间返回 true。
GetMouseButtonUp 在用户释放给定鼠标按钮的帧期间返回 true。
以上三个方法主要用于鼠标按键的获取,其中参数值为 0 表示左按钮,1 表示右按钮,2 表示中间按钮。至于鼠标的位置信息则是通过静态变量mousePosition来获取到的。该静态变量是一个三维向量Vector3类型,对应的就是游戏窗口坐标系的x,y,z三个坐标值。请注意的是,游戏窗口坐标系的原点是左下角,并且z值一直都是0。接下来,我们同样使用脚本来说明鼠标按键的信息获取。
if (Input.GetMouseButton(0))
{
Debug.Log("鼠标左键");
Debug.Log("鼠标位置:" + Input.mousePosition);
}
if (Input.GetMouseButton(1))
{
Debug.Log("鼠标右键");
}
if (Input.GetMouseButton(2))
{
Debug.Log("鼠标中键");
}
if (Input.GetMouseButtonDown(0))
{
Debug.Log("鼠标左键按下");
}
if (Input.GetMouseButtonUp(0))
{
Debug.Log("鼠标左键按上");
}
接下来,我们重新运行整个工程,然后依次按下鼠标左键,右键和中键,然后查看控制台输出,截图如下
与获取键盘按键方法是相似的,对于一次鼠标点击事件,GetMouseButton方法会多次调用,而GetMouseButtonUp 和 GetMouseButtonDown只会调用一次。Input.mousePosition输出位置坐标信息。请大家在使用的时候,一定要注意方法调用的次数。
GetAxis 返回由 axisName 标识的虚拟轴的值。
GetAxisRaw 返回由 axisName 标识的虚拟轴的值(未应用平滑过滤)。
GetButton 当按住 buttonName 标识的虚拟按钮时,返回 true。
GetButtonDown 在用户按下由 buttonName 标识的虚拟按钮的帧期间返回 true。
GetButtonUp 在用户释放由 buttonName 标识的虚拟按钮的第一帧返回 true。
上面的方法,主要用于“虚拟轴”和“虚拟按钮”。游戏中需要用到的按键分为两种,一种是开关键,就是只能两个状态的键(按下和按上),键盘上面的按键就属于此类。另一种是线性键(也就是“轴”键),它的键值是在一个范围内取值的(比如-1到1之间),例如游戏手柄中控制前后左右的的摇杆。不管是“虚拟轴”和“虚拟按钮”,在Unity中统一使用“Axes”输入轴来表示(当轴键只有-1和1的时候就是按钮键)。Unity的输入轴与设备无关,它可以用于鼠标,键盘,游戏手柄以及其他设备。每种设备的按键都有自己的编号名称,他们都可以在Unity中被设置为对应的输入轴。Unity的输入轴都有一个自定义的名称,GetAxis方法和GetButton的参数就是输入轴的名称,只不过两个方法的返回值是不一样的。
bool Input.GetButton(“虚拟按钮”):该方法可读取虚拟按钮,而不用关心真实绑定的键来源于鼠标,或者键盘,或者其他控制设备。它仅判断有没有键被按下或者抬起,无法判断方向是左,还是右。因此该方法的返回值是一个布尔类型。
float Input.GetAxis(“虚拟轴”):即能判断有没有键被按下或者抬起,又能判断方向,返回值是一个-1到1之间的浮点数,值为0表示没有键被按下。[-1,0)表示有键被按下,方向左,(0,1]表示有键被按下,方向右。
由此可见,Unity的输入轴就是为了解决各种输入设备而设计的一个统一解决方案。我们点击菜单栏“Edit”->“Project Settings……”,在弹出的窗口左侧找到“Input Manager”,如下
首先是Size值,它代表Unity设置了18个不同的输入轴。当然我们还可以修改这个数值,增加我们自定义的输入轴。接下来,我们简单介绍几个Unity预定义的几个输入轴。首先是“Horizontal”水平轴和“Vertical”垂直轴。他们主要用于前后左右的方向信息输入。其中“Horizontal”就是左右方向的信息输入,而“Vertical”就是前后方向的信息输入。
请注意,每一种输入轴的配置参数都是一样的。我们简单介绍一下。
Name:输入轴的名称,可以在脚本中直接使用。比如:Input. GetAxis (“Vertical”);
Descriptive Name: 当输入值为正数时候所显示的名称。默认空白。
Negative Descriptive Name:当输入值为负数的时候所显示的名称。默认空白。
Nagative Button:负向按键名称。也就是说,我们指定使用设备的那个按键来获取负数输入值。对于水平和垂直轴来讲,对应的是键盘上面的方向键“left”和“down”。
Positive Button:正向按键名称。同理指定使用设备的那个按键类获取正数输入值。对于水平和垂直轴来讲,对应的是键盘上面的方向键“right”和“up”。
为什么会有正向和负向的区别呢?其实对于“虚拟按钮”而言,它只有两个状态值,因此正数和负数意义并不大。但是,对于“虚拟轴”而言,它的返回值为“-1”到“1”之间。如果正数代表一个方向的话,那么负数就代表另一个方向,并且数值的大小还可以表示按键按下的程度。因此,使用正负数来表示一个维度上面的两个方向是比较合适的。请注意,这两个正负按键设置可以是键盘上的键,也可以是游戏杆或鼠标上的按钮。我们只需要填写设备按键的名称即可。这里的“left”,“right”,“up”,“down”对应的是键盘上面的方向键。大家应该在很多游戏中,都会使用键盘方向键来控制前后左右的信息输入。
Alt Negative Button:备选负向按键名称。也就是说,我们还可以使用设备上其他按键获取负数输入值。对于水平和垂直轴来讲,对应的是键盘上的字母键“A”和“S”。
Alt Positive Button:备选正向按键名称。同理指定使用设备上其他按键获取正数输入值。对于水平和垂直轴来讲,对应的是键盘上面的字母键“D”和“W”。
很明显,这里的备选按钮设置的是键盘上面的“WASD”的字母键设置。大家应该在很多游戏中,都会使用键盘上面的“WASD”键来控制前后左右的信息输入。
Gravity:重力。如果玩家停止输入,该输入轴将恢复到空挡或0速度,其单位为单位每秒。
Dead:盲区。在模拟控制器上,在这个范围内的任何值都会映射到空档不会提供任何输入。
Sensitivity:灵敏度。输入轴向目标值移动的速度。单位为单位每秒。
以上三项主要是输入轴使用的优化设置。
Snap:捕捉。如果启用,当按下相反方向的按钮,该输入轴的值将重设为0。默认启用。
Invert:反转。如果启用,则交换正向和负向控制键。默认不启用。
以上两项主要是输入轴使用的设置。
Type:类型。设置输入设备类型。可以为Key or MouseButton,Mouse Movement,Joystick Axis。默认是Key or MouseButton键盘或鼠标。所有的按钮(包括游戏手柄的按钮)输入都应设置为Key or MouseButton类型,对于鼠标移动(不是鼠标点击)和滚轮应设为Mouse Movement 类型,对于摇杆应该设为Joystick Axis类型。如果设置为Joystick Axis类型,我们接入游戏手柄设备之后,就可以使用摇杆来控制前后左右的信息输入。
Axis:轴。设置输入设备的输入轴。对于水平和垂直轴来讲,对应的是“X axis”和“Y axis”两个默认值。当然,我们还可以选择其他输入轴。其中前三种分别是X axis代表X轴、Y axis代表Y轴、3rd axis代表滚轮,后面的都是摇杆的输入轴。
JoyNum:摇杆编号。设置使用设备上的哪个摇杆。默认是接收所有摇杆的输入。
接下来,我们来看一看“Fire1”,“Fire2”,“Fire3”和“Jump”的输入轴设置。
根据Positive Button和 Alt Positive Button的设置可知,名称为“Fire1”的输入轴对应的是键盘上面的左Ctrl键以及鼠标左键。同理,“Fire2”输入轴对应的是键盘上面的左Alt键以及鼠标右键。同理,“Fire3”输入轴对应的是键盘上面的左Shift键以及鼠标中键。最后,“Jump”输入轴对应的只有键盘上面的空格键(没有备选按按键)。
float x = Input.GetAxis("Horizontal");
if (x != 0)
{
Debug.Log("Horizontal X :" + x);
}
float y = Input.GetAxis("Vertical");
if (y != 0)
{
Debug.Log("Vertical :" + y);
}
bool ctrl = Input.GetButtonUp("Fire1");
if (ctrl)
{
Debug.Log("ctrl :" + ctrl);
}
接下来,我们就可以运行工程,然后按下键盘方向键或者WASD键进行水平方向和垂直方向的测试,还可以按下左Ctrl键或者鼠标左击来测试“Fire1”的输入。截图如下
接下来是鼠标左键“Mouse X”,鼠标右键“Mouse Y”,鼠标滚轮中键“Mouse ScrollWheel”三个输入轴对应的设置。我们先看截图
对于鼠标移动的输入,我们不需要指定Button,而是应该指定Type为Mouse Movement类型,然后对应的Axis就是“X axis”,“Y axis”,“3 rd axis(Joystick and Scrollwheel)”三个。这样,我们就可以使用“Mouse X”,“Mouse Y”和“Mouse ScrollWheel”获取到鼠标移动的输入信息。那么他们返回什么数据呢?对于“Mouse X”和“Mouse Y”代表的是鼠标的移动方向,负值代表左下方向移动,正值代表右上方向移动,而数值的大小可以理解为偏移量(数值为-1到1之间,表示前后鼠标位置的差异)。而“Mouse ScrollWheel”代表的是鼠标中键前后滚动方向,负值代表向后滚动,正值代表向前滚动。我们可以使用代码来验证。
float mx = Input.GetAxis("Mouse X");
if (mx != 0)
{
Debug.Log("Mouse X :" + mx);
}
float my = Input.GetAxis("Mouse Y");
if (my != 0)
{
Debug.Log("Mouse Y :" + my);
}
float mz = Input.GetAxis("Mouse ScrollWheel");
if (mz != 0)
{
Debug.Log("Mouse ScrollWheel :" + mz);
}
请注意,Input.GetAxis("Mouse X")返回的是鼠标移动的偏移量,并不是获取鼠标点击事件,也不是鼠标在屏幕上面的位置坐标。这个偏移量可以用来表示鼠标的前后移动方向,可以将其转换为向量应用到游戏角色控制当中。我们场景中控制方向有很多不同的方式。键盘操作游戏角色移动,这个是最简单的,只需要参考自身坐标系前后左右移动即可。鼠标控制游戏角色移动分为两种方式,一种是鼠标移动控制游戏角色移动;另一种是鼠标点击控制角色移动。但是,两者的代码控制逻辑是一样的。他们两者的实现逻辑根据鼠标的2D坐标位置换算成场景中的3D坐标位置,然后根据前后两个坐标位置计算得出三维向量(偏移量),这个三维向量就是游戏角色移动的方向。当然,具体的操作应该是游戏角色旋转到目标方向(游戏角色看向目标点),然后依据自身坐标系向前移动即可。因此,这里最重要的就是这个代表方向的三维向量。这个可以使用向量减法来实现。而根据鼠标2D坐标位置换算成场景中的3D坐标位置,则是由变换矩阵或是射线来完成的。
总结:关于按键的输入,我们可以使用GetButton,GetButtonDown,GetButtonUp来获取按键的状态。这里的按键可以是键盘,鼠标按键,游戏手柄按钮,或者其他设备按键。这三个方法在游戏交互中已经足够使用了。至于鼠标位置信息的获取,其实我们使用的并不是很多。对于NGUI来讲,UI元素的事件属性已经可以帮我们处理大部分的交互逻辑了。
接下来我们发现Unity又给我们重复了几个输入轴。
其中,Horizontal,Vertical,Fire1,Fire2,Fire3,Jump是重复定义的。但是他们针对的是游戏手柄。我们以Horizontal举例查看
我们并没有设置对应的Button名称,而是设置Type为Joystick Axis为摇杆,同时设置Axis为 X axis使用游戏手柄的默认输入轴(摇杆的默认X轴)。在Joy Num中设置为任意摇杆输入。这样的设置,就会将游戏手柄的默认主摇杆设置为Unity的“Horizontal”输入轴。那么,我们就可以通过Input.GetAxis("Horizontal "); 来获取游戏手柄默认主摇杆水平X轴的输入。同理,也可以通过Input.GetAxis("Vertical "); 来获取游戏手柄默认主摇杆垂直Y轴的输入。接下来,我们在看看Fire1,Fire2,Fire3,Jump的设置,以Fire1为例说明
在“Positive Button”一项中我们设置的游戏手柄的按键名称为“Joystick Button 0”,它对应的就是游戏手柄上的“A”按键。并且Type一项又设置为按键类型了。如下图所示:
上图是我们经常使用的游戏手柄。他有两个摇杆,一个方向键盘,四个按钮(ABXY)按钮组成,当然在前侧面的两边还有LB,RB按键以及两个扳机键。这些按键都有自己的名称。
A: Joystick Button 0
B: Joystick Button 1
X: Joystick Button 2
Y: Joystick Button 3
LB:Joystick Button 4
RB:Joystick Button 5
……
这里就明白为什么我们在Unity中设置“Positive Button”的名称为什么是“Joystick Button 0”了吧。接下来,在Unity中剩余Fire2,Fire3,Jump三个输入轴对应的就是游戏手柄的Joystick Button 1,Joystick Button 2和Joystick Button 3,也就是上图中的B,X,Y三个按钮。接下来,我们就使用代码来测试一下
float jx = Input.GetAxis("Horizontal");
if (jx != 0)
{
Debug.Log("Joystick X :" + jx);
}
float jy = Input.GetAxis("Vertical");
if (jy != 0)
{
Debug.Log("Joystick Y :" + jy);
}
bool a = Input.GetButtonUp("Fire1");
if (a)
{
Debug.Log("Joystick A :" + a);
}
这次我们将游戏手柄接入Unity,然后运行当前工程,不要使用鼠标和键盘,直接使用转动游戏手柄的默认主摇杆,在按下A按钮进行测试。
本课程涉及的内容已经共享到百度网盘:https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id