目录
新版的InputSystem
安装新版InputSystem插件
配置新的InputSystem
在项目中配置新版输入方式实现移动和开火
添加并绑定移动事件
添加并绑定开火事件
总结(啰嗦几句)
新版的InputSystem
在最初的Unity系统中,只有键盘、鼠标、操作手柄等常见的输入设备,但随着数码产品的不断升级,越来越多的输入方式出现在游戏使用过程中,比如手机、XBox、switch,还有VR、AR设备等,因此旧的InputSystem已经不再方便,新的InputSystem应运而生。并且,新的InputSystem运基于事件中心的设计方式,将输入设备与动作逻辑相分离,而通过配置、映射对输入信息进行处理,更符合我们现在的项目设计理念。
安装新版InputSystem插件
在前面的文章中我们多次使用到了Input.GetAxis("Mouse X")等方法,这些都是在Unity自带的Input Manager中设置的(位置:Edit->ProjectSettings->InputManager)
新版的InputSystem可以在Window->PackageManager中,选择UnityRegistry,在列表中找到InputSystem,点击安装,等待自动安装进度即可:
下载完成后,Unity会自动安装并重启,在Packages文件夹中就能看到InputSystem:
安装完成后,在有些组件使用时需要重新设置一下,比如在使用UI控件时,UI的EventSystem会显示一个警告,只要点击按钮,同意使用新版的InputSystem即可:
在PackageManager->InputSystem中,还有许多的示例可以下载参考:
配置新的InputSystem
1. 在菜单Edit->ProjectSettings中,选择Player->OtherSettings->Configuration->Active Input Handling* 中可以选择使用老版还是新版的InputSystem,如果两者都需要,可以选择"Both"
2. 在同一面板中,选择“InputSystemPackage”,点击“Create settings asset”按钮,这样在Assets文件夹下就会新建一个InputSystem.inputsettings的配置文件,在InputSystemPackage面板中的设置将会被记录在这个文件中
在项目中配置新版输入方式实现移动和开火
1. “Player Input”组件:在场景的空节点上点击“Add Component”按钮,挂载“Player Input”组件。建议挂载在SingleMono上,这是挂载所有Mono单例的脚本的节点,它在场景切换时不会被消除,详见(单例)
2. 新建配置文件:在放Input脚本的文件夹上点右键,"Create->Input Actions(最下面)",将新建的配置文件设置一个名字,这里叫做“Input Controls”,然后点击“Edig asset”配置文件。
3. 配置Player移动的输入:在弹出的面板中“ActionMap”按“+”号,新建一个输入配置的组,可以根据需要修改名称,这里改成了”PlayerMap“。在右边的"Action"栏中就是管理各种移动、开火、点击等输入的配置,也可以根据需要修改"New Action"的名字:
4. 绑定输入,这里以主角在场上的移动为例,它的移动是在XZ平面上的,因此要添加一个二维向量的输入,获取输入的数值。在右边的“Action Type”中,选择类型为"Value",下面的“Control Type”为Vector2
5. 点击"Action->Move"右边的“+”号,添加绑定一个监听“Add Positive\Negative Binding”,会加入一个“2DVector”的项目:
自动会在“2D Vector”下面出现上、下、左、右四个方向的绑定。在右边的Path下拉菜单中,可以看到各种输入设备,根据需要选择合适的输入,有摇杆、键盘、鼠标……直接在搜索栏中输入按键即可,这里还是使用W按键:
6. 按照同样的方式设置开火fire。开火只要一个按钮按下即可,所以“Action Type”选择为“Button"即可,这里开火按钮设置为Space按键:
7. 设置完成后,保存并退出。将SingleMono节点上的”Player Input“组件的"Action"设置为上面配置好的InputControls文件。
在DefaultMap中可以看到上面配置完成的PlayerMap这一项,现在它是默认的输入项目。
添加并绑定移动事件
(设置方式与UI中的按钮监听事件比较相同)
1. 在"PlayerInput"组件的下方,设置事件“Event”。这里能够看到上面设置的"Move"和"Fire"两个输入响应的项目。分别点击这两个项目下面的+号,然后绑定脚本中设置的相应事件:
2. 在脚本中注册并发送事件,以主角移动为例。
关于事件的概念以及事件中心的建立详见(事件中心、InputManager),这里不再赘述。仅记录一下关于主角移动,如何以监听事件的方式发送移动数据和实现移动。
(1)修改之前写的HeroMove.cs(组件2--Rigidbody--移动控制),这是挂在主角身上控制主角移动的脚本,在其中注册一个移动事件,并发送数据(移动位置的二维向量)
public class HeroMove : MonoBehaviour
{
private Rigidbody rb;
private Vector2 moveInput;
private Vector3 movement;
private Quaternion targetRotation;
public float moveSpeed = 2;
public float rotateSpeed = 2;
GameObject Bullet;
void Start()
{
rb = GetComponent<Rigidbody>();
//增加
EventManager.Instance.AddEvent(EventType.OnPlayerMove, this, data =>
{ //注册一个移动的事件,这个事件由InputManager中的OnMove发送给
//场景中的PlayerInput绑定监听
var eventData = data as EventDataPlayerMove;
moveInput= eventData.position; //传递移动时的XZ方向的位置
});
}
void FixedUpdate()
{
//删除:
//moveInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")); //坐标数据不再由Input.GetAxis获得
//下面都一样
movement.Set(moveInput.x, 0, moveInput.y);//坐标数据通过事件数据发送
movement.Normalize();
//检测是否有输入
bool hInput = !Mathf.Approximately(moveInput.x, 0);
bool vInput = !Mathf.Approximately(moveInput.y, 0);
if (hInput || vInput)
{
movement = Quaternion.Euler(0, Camera.main.transform.eulerAngles.y, 0) * movement;
}
Vector3 lookForward = Vector3.RotateTowards(transform.forward, movement, rotateSpeed * Time.fixedDeltaTime, 360);
targetRotation = Quaternion.LookRotation(lookForward);
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
rb.MoveRotation(targetRotation);
}
}
(2)另外,新建脚本(或直接在InputManager.cs中)添加发送事件。(其中关于SendEvent、EventType、InputManager等定义详见事件中心、InputManager)
public class InputManager : SingleMono<InputManager>
{
//定义移动和开火的事件
public void OnMove(InputAction.CallbackContext context)
{//绑定新版InputSystem中的PlayerMap-Move事件
EventManager.Instance.SendEvent(EventType.OnPlayerMove, new EventDataPlayerMove()
{
position=context.ReadValue<Vector2>()
});
}
public void OnFire(InputAction.CallbackContext context)
{//绑定新版InputSystem中的PlayerMap-Fire事件
EventManager.Instance.SendEvent(EventType.OnPlayerFire, null);
}
}
3. 将上面这个InputManager.cs挂载在场上的单例节点上(所有继承SingleMono的脚本都挂在这里,详见单例)
4. 把挂有发送事件的脚本(现在是InputManager.cs)的节点(SingleMono)拖到Object这栏:
并在监听的函数这栏点小三角形,选脚本名称,就看到上面已经定义好的两个监听函数,这里控制的是移动,因此选择“OnMove”函数:
添加并绑定开火事件
1. 注册一个开火事件:随便新建一个脚本,挂载在主角身上(其他GO也可以),在其中注册一个事件,并设置回调callback
public class BulletFireEvent : MonoBehaviour
{
public GameObject bullet;
void Start()
{
EventManager.Instance.AddEvent(EventType.OnPlayerFire, this, callback =>
{
bullet = Resload.Instance.LoadPrefab("Bullet");//从资源库加载
bullet.SetActive(true);
//赋予子弹初始值和角度
bullet.transform.position = transform.position;
bullet.transform.rotation = transform.rotation;
Destroy(bullet, 2);//2秒后销毁
});
}
}
2. 与上面设置OnMove函数一样,在Event->PlayerMap->Fire中设置OnMove函数:
总结(啰嗦几句)
1. 按上面的设置,运行的效果与没有使用新版InputSystem和事件中心是一样的,所以就不在放运行结果的图了;
2. 上面的脚本使用的是自定义的事件中心(EventManager),这是项目设计中的重要一环(详见EventManager--事件中心),当然也可以使用Unity定义的事件管理;
3. 在PlayerInput中的监听函数设置,也可以在脚本中完成,与UI系统中的按钮监听是很相似的;
4. 需要其他功能,可以到Windows->PackageManager->InputSystem中下载示例,参照它的设置方式;
5. 使用InputSystem的优点:原先我们在制作第一人称控制器时,用了很多的if来拿到输入按键(详见第一人称控制器),如果在项目中需要多次使用键盘输入,就有可能需要修改多处键盘按键,而使用InputSystem只要在面板中直接修改输入方式的定义即可,非常方便!