InputSystem
一、InputSystem简介
InputSystem是Unity提供的更好的一种输入系统,相对的Unity的老输入系统是InputManager。现在大部分公司都是使用新版的输入系统。老系统和新系统的区别在于:老系统需要我们自己去写代码,来检测按键的输入。但是新输入系统我们不需要再写代码来检测按键输入了。我们在新的输入系统中,只需要写关于按键之后的逻辑部分的代码。
二、教程
Lesson1-InputSystem的导入
在使用新版输入系统InputSystem之前,我们需要先导入它:Window–Packge Manager。将左上角选为Unity Registty模式,之后在右上角搜索框搜索InputSystem,点击Install即可。注意:安装后会重启Unity。
在安装完成之后,可以在File–Build Setting–Player Setting–Other–Active Input Handing 中选择使用哪一种输入系统,可以同时启用新老两种输入系统。主意:在重新选择后会重启Unity。并且如果只启用新输入系统,再使用老输入系统的话,Unity会报错,所以可以选择Both将两种输入系统都启用。
Lesson2-键盘输入
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Lesson2 : MonoBehaviour
{
Keyboard keyboard;
void Start()
{
#region 知识点一 获取当前键盘设备(需要引用命名空间)
//新输入系统 提供了对应的输入设备类 帮助我们对某一种设备输入进行检测
//注意后面不能new 要去.current 代表获得我们当前激活使用的键盘
keyboard = Keyboard.current;
#endregion
#region 知识点二 判断键盘的单个按键 按下 抬起 长按
//通过键盘类对象 点出 单个按键 来获取
//按下
if (keyboard.aKey.wasPressedThisFrame)
{
}
//抬起
if (keyboard.sKey.wasReleasedThisFrame)
{
}
//长按
if (keyboard.spaceKey.isPressed)
{
}
#endregion
#region 知识点三 得到键盘的哪个键按下
//通过给keyboard对象中的 文本输入事件 添加委托函数
//可以得到键盘按下的是哪一个字符
//方法的参数是一个char char就是按下的字符
keyboard.onTextInput += (c) =>
{
print("键盘按下的是" + c + "键");
};
#endregion
#region 知识点四 任意键按下监听
//可以处理 任意键 按下 抬起 长按 相关的逻辑
if (keyboard.anyKey.wasPressedThisFrame)
{
}
//.wasPressedThisFrame
//.wasReleasedThisFrame
//.isPressed
#endregion
}
void Update()
{
//在update中测试
if (keyboard.aKey.wasPressedThisFrame)
{
print("a键按下");
}
if (keyboard.sKey.wasReleasedThisFrame)
{
print("s键抬起");
}
if (keyboard.spaceKey.isPressed)
{
print("空格键长按中");
}
if (keyboard.anyKey.wasPressedThisFrame)
{
print("任意键按下");
}
}
}
Lesson3-鼠标输入
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Lesson3 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 知识点一 获取当前鼠标设备(需要引用命名空间)
//和前面的键盘一样 要先获取我们使用的鼠标
Mouse mouse = Mouse.current;
#endregion
#region 知识点二 鼠标各个键位 按下 抬起 长按
//鼠标左键
//mouse.leftButton;
//鼠标右键
//mouse.rightButton;
//鼠标中键
//mouse.middleButton;
//鼠标侧键(前后)
//mouse.forwardButton;
//mouse.backButton;
if (mouse.leftButton.wasPressedThisFrame)
{
}
if (mouse.leftButton.wasReleasedThisFrame)
{
}
if (mouse.leftButton.isPressed)
{
}
#endregion
#region 知识点三 鼠标位置相关
//获取鼠标当前位置
//注意这个position是Mouse封装了的 如果要得到具体位置的值 需要.ReadValue();
mouse.position.ReadValue();
//获得鼠标这一帧 和上一帧的偏移量
mouse.delta.ReadValue();
//获得鼠标滚轮的值(方向向量)
mouse.scroll.ReadValue();
#endregion
}
// Update is called once per frame
void Update()
{
if (Mouse.current.leftButton.wasPressedThisFrame)
{
print("左键按下");
}
if (Mouse.current.leftButton.wasReleasedThisFrame)
{
print("左键抬起");
}
if (Mouse.current.rightButton.isPressed)
{
print("右键长按");
}
if (Mouse.current.forwardButton.isPressed)
{
print("前侧键长按");
}
//print(Mouse.current.position.ReadValue());
//print(Mouse.current.delta.ReadValue());
print(Mouse.current.scroll.ReadValue());
}
}
Lesson4-触屏输入
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem;
public class Lesson4 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 知识点一 获取当前触屏设备
Touchscreen ts = Touchscreen.current;
//由于触屏相关都是在移动平台或提供触屏的设备上使用
//所以在使用时最好做一次判空
if (ts == null)
return;
#endregion
#region 知识点二 得到触屏手指信息
//得到触屏手指数量
print(ts.touches.Count);
//得到单个触屏手指
print(ts.touches[0]);
//得到所有触屏手指
foreach (var t in ts.touches)
{
}
#endregion
#region 知识点三 手指按下 抬起 长按 点击
//获取指定索引手指
print(ts.touches[0]);
//要判断是否抬起等等 要先获得这根手指的信息
TouchControl tc = ts.touches[0];
//按下 抬起
if (tc.press.wasPressedThisFrame)
{
}
if (tc.press.wasReleasedThisFrame)
{
}
//长按
if (tc.press.isPressed)
{
}
//点击手势
if (tc.tap.isPressed)
{
}
//连续点击次数
print(tc.tapCount);
#endregion
#region 知识点四 手指位置等相关信息
//位置
print(tc.position.ReadValue());
//第一次接触时位置
print(tc.startPosition.ReadValue());
//接触区域大小
print(tc.radius.ReadValue());
//和上一帧的偏移位置
print(tc.delta.ReadValue());
//得到当前手指的 状态(阶段)
UnityEngine.InputSystem.TouchPhase tp = tc.phase.ReadValue();
switch (tp)
{
//无状态
case UnityEngine.InputSystem.TouchPhase.None:
break;
//手指开始接触屏幕
case UnityEngine.InputSystem.TouchPhase.Began:
break;
//手指开始在屏幕上移动
case UnityEngine.InputSystem.TouchPhase.Moved:
break;
//手指结束移动
case UnityEngine.InputSystem.TouchPhase.Ended:
break;
//手指取消移动
case UnityEngine.InputSystem.TouchPhase.Canceled:
break;
//静止 手指没动了
case UnityEngine.InputSystem.TouchPhase.Stationary:
break;
default:
break;
}
#endregion
}
// Update is called once per frame
void Update()
{
}
}
Lesson5-手柄输入
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Lesson5 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 知识点一 获取当前手柄
Gamepad gp = Gamepad.current;
//判断是否得到手柄
if(gp == null)
{
return;
}
#endregion
#region 知识点二 手柄摇杆
//摇杆方向
//左摇杆
print(gp.leftStick.ReadValue());
//右摇杆
print(gp.rightStick.ReadValue());
//摇杆按下 抬起 长按
//左摇杆
if (gp.leftStickButton.wasPressedThisFrame)
{
}
if (gp.leftStickButton.wasReleasedThisFrame)
{
}
if (gp.leftStickButton.isPressed)
{
}
//右摇杆
#endregion
#region 知识点三 手柄方向键
//对应手柄上4个方向键 上下左右
//gamePad.dpad.left
//gamePad.dpad.right
//gamePad.dpad.up
//gamePad.dpad.down
//按下 抬起 长按
if (gp.dpad.left.wasPressedThisFrame)
{
}
if (gp.dpad.left.wasReleasedThisFrame)
{
}
if (gp.dpad.left.isPressed)
{
}
#endregion
#region 知识点四 手柄右侧按键
//通用
//东西南北
//Y、△
//北方(上方) gp.buttonNorth
//A、X
//南方(下方) gp.buttonSouth
//X、□
//西方(左方) gp.buttonWest
//B、○
//东方(右方) gp.buttonEast
//它们的按下抬起长按和上面一致
//wasPressedThisFrame
//wasReleasedThisFrame
//isPressed
//不建议这样使用 因为不同手柄的名称都是不一样的 而上面的东西南北是通用的
//手柄右侧按钮 x ○ △ □ A B Y
//○
//gamePad.circleButton
//△
//gamePad.triangleButton
//□
//gamePad.squareButton
//X
//gamePad.crossButton
//x
//gamePad.xButton
//a
//gamePad.aButton
//b
//gamePad.bButton
//Y
//gamePad.yButton
#endregion
#region 知识点五 手柄中央按键
//中央键
//gp.startButton;
//gp.selectButton;
//wasPressedThisFrame
//wasReleasedThisFrame
//isPressed
#endregion
#region 知识点六 手柄肩部按键
//左上右上 肩部键位
//左右前方肩部键
//gp.leftShoulder;
//gp.rightShoulder;
//左右后方触发键(油门键)
//gamePad.leftTrigger
//gamePad.rightTrigger
//wasPressedThisFrame
//wasReleasedThisFrame
//isPressed
#endregion
}
// Update is called once per frame
void Update()
{
}
}
Lesson6-其他输入
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson6 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 知识点一 新输入系统中的输入设备类
//常用的
//Keyboard—键盘
//Mouse—鼠标
//Touchscreen—触屏
//Gamepad—手柄
//其它
//Joystick—摇杆
//Pen—电子笔
//Sensor(传感器)
//https://docs.unity3d.com/Packages/[email protected]/manual/Sensors.html#accelerometer
//Gyroscope—陀螺仪
//GravitySensor—重力传感器
//加速传感器
//光照传感器
//等等
#endregion
#region 知识点二 关于没有细讲的设备
//对于我们没有细讲的设备
//平时在开发中不是特别常用
//如果想要学习他们的使用
//最直接的方式就是看官方的文档
//或者直接进到类的内部查看具体成员
//通过查看变量名和方法名即可了解使用方式
//UnityEngine.InputSystem.Gyroscope g = UnityEngine.InputSystem.Gyroscope.current;
//g.angularVelocity.ReadValue()
#endregion
#region 知识点三 注意事项
//新输入系统的设计初衷就是想提升开发者的开发效率
//我们不提倡写代码来处理输入逻辑
//之后我们学了配置文件相关知识后
//都是通过配置文件来设置监听(监视窃听)的输入事件类型
//我们只需要把工作重心放在输入触发后的逻辑处理
//所以我们目前讲解的知识都是为了之后最准备
//实际开发中使用较少
#endregion
}
// Update is called once per frame
void Update()
{
}
}
Lesson7-InputAction
在之前我们都需要通过手动写代码的形式来绑定监听哪个键输入了,现在我们可以使用InputAction,直接在界面上来绑定监听哪个键输入了。在界面上确定了监听哪个键之后。我们只需要在代码中去处理,按键触发后的逻辑就行了。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using static UnityEngine.InputSystem.Controls.AxisControl;
public class Lesson7 : MonoBehaviour
{
//声明一些InputAction
[Header("单个按钮")]
public InputAction move;
[Header("1D轴")]
public InputAction axis;
[Header("2D轴")]
public InputAction vector2D;
[Header("3D轴")]
public InputAction vector3D;
[Header("双键组合")]
public InputAction one;
[Header("三键组合")]
public InputAction two;
void Start()
{
#region 知识点一 InputAction是什么?
//顾名思义,InputAction是InputSystem帮助我们封装的输入动作类
//它的主要作用,是不需要我们通过写代码的形式来处理输入
//而是直接在Inspector窗口编辑想要处理的输入类型
//当输入触发时,我们只需要把精力花在输入触发后的逻辑处理上
//我们在想要用于处理输入动作的类中
//申明对应的InputAction类型的成员变量(注意:需要引用命名空间UnityEngine.InputSystem)
//之后就可以在Unity的Inspector窗口上面来编辑它们了
#endregion
#region 知识点二 InputAction参数相关
//接下来我们讲解Inspector窗口上的参数
//参数分为三部分
#region 按钮一:齿轮
#region Action:输入动作设置
//Action Type:动作类型(就是选择是要得到设备的返回值 还是 得到按钮是否按下)
//Value:值类型 主要用于状态连续更改的输入,例如鼠标的移动,手柄的遥感。如果有多个设备绑定这个 Action,只会发送其中一个设备(最受控制的)的输入
//Button:按钮类型 用于每次按下时触发的 Action
//Pass Through:直通类型 和 Value 一样,区别在于如果有多个设备绑定这个 Action,会发送所有设备的输入
//Control Type:控制类型(就是进行一次返回值筛选 选出你要得到的值是什么 例如只需要得到vector2)
//Any 任何值
//Integer 整数
//Axis 一维轴浮点数,例如:摇杆输入返回值
//Quaternion 四元数
//Bone 骨骼
//Stick 摇杆相关
//Digital 数字
//Touch 触屏相关
//Dpad 4 向按钮,例如:摇杆上的 D-pad
//Vector2 2 维向量
//Eyes VR 相关数值
//Vector3 3 维向量
//在这里选择对应的类型,之后在选择对应设备按键相关属性时,
//会根据你选择内容的不同,筛选对应内容这上面显示的内容就是各设备属性的返回值类型
//当你选择他们后,非选择的类型将不会在之后的按键设置中出现
//很多内容我们基本用不到,相当于是在这里筛选输入设备
#endregion
#region Interactions:相互作用设置
//用于特殊输入,比如长按、多次点击等等,当满足条件时才会触发这个行为(设置长按时间、点击次数等等)
//默认关联了以下 3 个输入事件,我们可以通过代码为事件添加监听逻辑:
//开始:Started
//触发:Performed
//结束:Canceled
//1.Hold:长按。
//适用于需要输入设备保持一段时间的操作。
//当按钮按下会触发 Started。
//若在松开按钮前,按住时间大于等于 Hold Time 则会触发 Performed(时间一到就触发)
//否则触发 Canceled。
//Press Point:在 Input System 中,每个按钮都有对应的浮点值,例如普通的按钮,将会在 0(未按下)和 1(按下)之间。
//因此我们可以利用这个值(Press Point)来进行区分,当大于等于这个值则认为按钮按下了。
//2.Tap:单击
//和 Hold 相反,需要在一段时间内按下松开来触发。
//当按钮按下会触发 Started
//若在 Max Tap Duriation 时间内(小于)松开按钮,触发 Performed
//否则触发 Canceled。
//3.SlowTap:长按并松开。
//类似 Hold,但是它在按住时间大于等于 Max Tap Duriation 的时候,并不会立刻触发 Performed,而是会在松开的时候才触发 Performed
//4.MultiTap:连击。
//用作于多次点击,例如双击或者三连击。
//Tap Count:点击次数
//Max Tap Spacing:每次点击之间的间隔(默认值为 2 * Max Tap Duration)
//Max Tap Duration:每次点击的持续时间,即按下和松开按钮的这段时间。
//当每次点击时间小于 Max Tap Duration,且点击间隔时间小于 Max Tap Spacing,点击 Tap Count 次,触发 Performed。
//5.Press:按下
//可以实现类似按钮的操作
//Press Only:按下的时候触发 Started和 Performed。不触发 Canceled
//Release Only:按下的时候触发 Started,松开的时候触发 Performed
//Press And Release:按下的时候触发 Started和 Performed,松开的时候会再次触发 Started和 Performed。不触发 Canceled
//PressPoint:在InputSystem中 每个按钮都有对应的默认值 例如普通按钮 将会在0(未按下)和1(按下)之间 我们可以利用这个值来区分
//当大于这个值 则被认为按下(有些按钮有浅按和全按的区分 可以利用它来区分)
#endregion
#region Processors:值处理加工设置
// 对得到的值进行处理加工
//1.Clamp:将输入值钳制到[min,max] 范围。
//2.Invert:反转控件中的值(即,将值乘以 - 1)。
//3.Invert Vector 2:反转控件中的值(即,将值乘以 - 1)。
//如果 invertX 为真,则反转矢量的 x 轴
//如果 invertY 为真,则反转矢量的 y 轴。
//4.Invert Vector 3:反转控件中的值(即,将值乘以 - 1)。
//如果反转 x 为真,则反转矢量的 x 轴
//如果反转 y 为真,则反转 y 轴
//如果反转 z 为真,则反转 z 轴
//5.Normalize:
//如果最小值 >= 0,则将[min,max] 范围内的输入值规格化为无符号规格化形式[0,1]
//如果最小值 < 0,则将输入值规格化为有符号规格化形式[-1,1]。
//6.Normalize Vector 2:将输入向量规格化为单位长度(1)。
//7.Normalize Vector 3:将输入向量规格化为单位长度(1)
//8.Scale:将所有输入值乘以系数。
//9.Scale Vector 2:将所有输入值沿 x 轴乘以 x,沿 y 轴乘以 y。
//10.Scale Vector 3:将所有输入值沿 x 轴乘以 x,沿 y 轴乘以 y,沿 z 轴乘以 z。
//11.Axis Deadzone:axis 死区处理器缩放控件的值,使绝对值小于最小值的任何值为 0,绝对值大于最大值的任何值为 1 或 - 1。
//许多控件没有精确的静止点(也就是说,当控件位于中心时,它们并不总是精确报告 0)。
//在死区处理器上使用最小值可避免此类控件的无意输入。
//此外,当轴一直移动时,某些控件不一致地报告其最大值。在死区处理器上使用最大值可确保在这种情况下始终获得最大值。
//12.Stick Deadzone:摇杆死区处理器缩放 Vector2 控件(如摇杆)的值,
//以便任何幅值小于最小值的输入向量都将得到(0,0),而任何幅值大于最大值的输入向量都将规格化为长度 1。
//许多控件没有精确的静止点(也就是说,当控件位于中心时,它们并不总是精确地报告(0,0)。
//在死区处理器上使用最小值可避免此类控件的无意输入。此外,当轴一直移动时,某些控件不一致地报告其最大值。
//在死区处理器上使用最大值可确保在这种情况下始终获得最大值。
#endregion
#endregion
#region 按钮二:加号
//1.Add Binding
//添加新的输入绑定(单按键输入)
//2.Add Positive \ Negative Binding 或者 Add 1D Axis Composite
//添加 1D 轴组合(类似 Input 中的水平竖直热键,返回 - 1 ~1 之间的一个值)
//3.Add Up \ Down \ Left \ Right Composite 或者 Add 2D Vector Composite
//添加 2D 向量组合(类似将 Input 中的水平竖直热键组合在一起,得到的 Vector 中的 x,y 分别表示两个轴)
//4.Add Up \ Down \ Left \ Right \ Forward \ Backward Composite
//添加 3D 向量组合
//5.Add Button With One Modifier Composite
//添加带有一个复合修改器的按钮(可以理解为双组合键, 比如 Ctrl +C、Ctrl + V)
//6.Add Button With Two Modifier Composite
//添加带有两个复合修改器的按钮(可以理解为三组合键,比如 Ctrl+K + U)
#endregion
#region 按钮三:减号
#endregion
#endregion
#region 知识点三 InputAction的使用
//第一点:想要使用这个InputAction的话 必须先启用输入检测
move.Enable();
//第二点:操作监听相关 它有三个事件
//1.开始状态
move.started += TestFunc;
//2.真正触发
move.performed += (context) =>
{
//第三点:关键参数 CallbackContext 我们可以通过context来得到很多信息
//1.当前动作的状态
print(context.phase); //没有启用:Disabled //等待:Waiting //开始:Started //触发:Performed //结束:Canceled
//2.当前动作的名字(其实这里的action就是一个属性 它会返回我们上面声明的InputAction,也就是move这个对象)
print(context.action.name);
//3.控件信息(哪一个键)
print(context.control.name);
//4.获取值
print(context.ReadValue<Vector2>());
//5.持续时间
print(context.duration);
//6.开始时间
print(context.startTime);
print("触发事件调用");
};
//3.结束状态
move.canceled += (callback) =>
{
print("结束事件调用");
};
axis.Enable();
vector2D.Enable();
vector3D.Enable();
one.Enable();
two.Enable();
axis.started += (callback) =>
{
print(callback.ReadValue<Vector2>());
};
one.started += (callback) =>
{
print("双组合键触发");
};
two.started += (callback) =>
{
print("三键组合触发");
};
#endregion
#region 知识点四 特殊输入设置
//1.Input System 基础设置(一些默认值设置)
//2.设置特殊输入规则
#endregion
}
public void TestFunc(InputAction.CallbackContext callbackContext)
{
print("开始事件调用");
}
void Update()
{
//因为axis是得到-1到1之间的数 一般用于2D控制人物 所以我们不太需要启用它的三个事件
//而是直接通过声明的InputAction 也就是axis对象 axis.ReadValue()来得到返回值就行了
//不需要启用事件 然后在使用事件中的参数context来获取值
//print(axis.ReadValue<float>());
//print(vector2D.ReadValue<Vector2>());
print(vector3D.ReadValue<Vector3>());
}
}
Lesson8-输入配置文件
在上一节课中,我们需要在代码中自己声明InputAction对象,虽然可以在界面中直接绑定按钮监听,从而不需要写代码了。但是我们还是需要自己在代码中去声明它。在这节课我们学习输入配置文件-InputActions之后,我们也不需要在代码中去声明InputAction对象了,我们可以直接在面板新建立一个InputActions,它是InputAction的集合,里面可以包含n个InputAction。更加的方便。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson8 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 知识点一 什么是输入配置文件?
//输入系统中提供了一种输入配置文件
//你可以理解它是InputAction的集合
//可以在一个文件中编辑多个InputAction的信息
//里面记录了想要处理的行为和动作(也就是InputAction的相关信息)
//我们可以在其中自己定义 InputAction(比如:开火、移动、旋转等)
//然后为这个InputAction关联对应的输入动作
//之后将该配置文件和PlayerInput进行关联
//PlayerInput会自动帮助我们解析该文件
//当触发这些InputAction输入动作时会以分发事件的形式通知我们执行行为
#endregion
#region 知识点二 编辑输入配置文件
//1.在Project窗口右键Create创建InputActions配置文件
//2.双击创建出的文件
//3.进行配置
#endregion
#region 知识点三 配置窗口参数相关
#endregion
}
// Update is called once per frame
void Update()
{
}
}
Lesson9-输入配置文件生成C#代码
在上节课我们学习了如何声明InputActions,这节课我们来学习如何使用这个InputAction的集合,也就是InputActions。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson9 : MonoBehaviour
{
Lesson9Input input;
// Start is called before the first frame update
void Start()
{
#region 知识点一 根据配置文件生成C#脚本
//1.选择InputActions文件
//2.在Inspector窗口设置生成路径,类名,命名空间
//3.应用后生成C#脚本
#endregion
#region 知识点二 使用C#代码进行监听
//我们为InputActions生成了对应的C#脚本 接下来的使用和InputAction的使用类似
//1.创建生成的脚本类对象
input = new Lesson9Input();
//2.激活输入
input.Enable();
//3.事件监听
//因为InputActions中有多套动作行为
//所以先使用声明的类对象.出来是使用的哪套输入动作
//再.出来 要使用的是哪个动作行为
//再.出来三个事件进行使用
input.Action1.Fire.performed += (callback) =>
{
print("开火了");
};
input.Action2.Space.performed += (callback) =>
{
print("跳跃了");
};
#endregion
}
// Update is called once per frame
void Update()
{
print(input.Action1.Move.ReadValue<Vector2>());
}
}
Lesson10-PlayerInput组件
上节课我们学习了如何使用InputActions,它需要我们去生成C#脚本文件,然后声明脚本类对象去使用。这样做实际很麻烦,所以我们学习PlayerInput组件,进一步的简化使用。只要将需要操控的对象身上挂载PlayerInput组件,然后将InputActions和组件上的actions关联,这样我们使用InputActions的时候,就不需要再去为它声明C#脚本了。而是通过PlayerInput组件上的Behavior去使用它上面声明的InputAction。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson10 : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
#region 知识点一 PlayerInput是什么?
//PlayerInput是InputSystem提供的
//专门用于接受玩家输入来处理自定义逻辑的组件
//主要工作原理
//1.配置输入文件(InputActions文件)
//2.通过PlayerInput关联配置文件,它会自动解析该配置文件
//3.关联对应的响应函数,处理对应逻辑
//好处:
//不需要自己进行相关输入的逻辑书写
//通过配置文件即可配置想要监听的对应行为
//让我们专注于输入事件触发后的逻辑处理
#endregion
#region 知识点二 添加PlayerInput组件
//选择任意对象(一般为一个玩家对象)
//为其添加PlayerInput组件
#endregion
#region 知识点三 PlayerInput参数相关
//1.Actions:选择一套InputActions和玩家关联。
// Default Scheme:默认启用哪一个设备(键盘鼠标或者手柄之类的)
// Auto - Switch:允许自动切换设备
// Default Map:默认启用哪一个Map
//2.UI Input Module:关联UI的EventSystem(需要使用UI来控制行为的时候,例如使用UI制作的虚拟摇杆控制人物移动等等)
//3.Camera:关联摄像机,当需要分屏设置时才会修改它 Behavior:如何通知游戏对象执行逻辑
//4.Behavior:
// Send Message:将逻辑脚本挂载在PlayerInput挂载的对象上 这样就可以通过Send Message通知执行对应函数
// Broadcast Message:将逻辑脚本挂载在PlayerInput挂载的对象上 或者挂载在子对象上 这样就可以通过Broadcast Message通知执行对应函数
// Invoke UnityEvent Actions:通过拖曳脚本关联函数 指明想要执行的函数
// Invoke CSharp Events:通过C#事件监听处理对应的逻辑 通过获取PlayerInput进行事件监听
#endregion
}
// Update is called once per frame
void Update()
{
}
}
Lesson11_Player Input行为执行模式
再上一节课我们初步认识了PlayerInput这个组件,也了解了上面的参数的含义。这节课我们就来仔细的学习,如何使用PlayerInput来使用InputActions,而不是通过声明C#脚本的形式来使用它。
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Timeline.Actions;
using UnityEngine;
using UnityEngine.InputSystem;
public class Lesson11 : MonoBehaviour
{
//使用第四种代码添加的形式 应该先得到PlayerInput这个组件
PlayerInput input;
void Start()
{
//建议使用第三和第四种 效率更高 因为不用去查找
#region 知识点一 Send Messages
//在自定义脚本中
//申明名为 "On+行为名" 的函数
//没有参数 或者 参数类型为InputValue
//将该自定义脚本挂载到PlayerInput依附的对象上
//当触发对应输入时 会自动调用函数
//并且还有默认的3个和设备相关的函数可以调用
//设备注册(当控制器从设备丢失中恢复并再次运行时会触发):OnDeviceRegained(PlayerInput input)
//设备丢失(玩家失去了分配给它的设备之一,例如,当无线设备耗尽电池时):OnDeviceLost(PlayerInput input)
//控制器切换:OnControlsChanged(PlayerInput input)
#endregion
#region 知识点二 Broadcast Messages
//基本和SendMessage规则一致
//唯一的区别是,自定义脚本不仅可以挂载在PlayerInput依附的对象上
//还可以挂载在其子对象下
#endregion
#region 知识点三 Invoke Unity Events
//该模式可以让我们在Inspector窗口上通过拖拽的形式关联响应函数
//它的好处是看起来更加清晰 而且不需要像上面一样 必须要将脚本挂载在PlayerInput依附的对象上(或子对象上)
//但是注意:响应函数的参数类型 需要改为 InputAction.CallbackContext
#endregion
#region 知识点四 Invoke C Sharp Events
//1.获取PlayerInput组件
input = GetComponent<PlayerInput>();
//2.获取对应事件进行委托函数添加
input.onControlsChanged += OnControlsChanged;
input.onDeviceLost += OnDeviceLost;
input.onDeviceRegained += OnDeviceRegained;
//不管触发了什么都会调用该函数 所以要通过传入的参数来具体判断触发了哪一种
input.onActionTriggered += onActionTrigger;
//3.当触发输入时会自动触发事件调用对应函数
#endregion
#region 知识点五 关键参数InputValue和InputAction.CallbackContext
//InputValue
//是否按下
//得到具体返回值
#endregion
}
void Update()
{
//第四种方式可以直接这样使用 来控制移动
print(input.currentActionMap["Move"].ReadValue<Vector2>());
}
#region Send Messages / Broadcast Messages
public void OnMove(InputValue value)
{
print("Move");
}
public void OnLook(InputValue value)
{
print("Look");
}
public void OnFire(InputValue value)
{
print("Fire");
}
public void OnDeviceRegained(PlayerInput input)
{
print("设备注册");
}
public void OnDeviceLost(PlayerInput input)
{
print("设备丢失");
}
public void OnControlsChanged(PlayerInput input)
{
print("设备切换");
}
#endregion
#region Invoke Unity Events
public void PlayerMove(InputAction.CallbackContext context)
{
print("人物移动");
}
public void PlayerFire(InputAction.CallbackContext context)
{
print("人物开火");
}
public void PlayerLook(InputAction.CallbackContext context)
{
print("人物Look");
}
#endregion
#region Invoke C Sharp Events
public void onActionTrigger(InputAction.CallbackContext context)
{
switch (context.action.name)
{
case "Move":
print(context.ReadValue<Vector2>());
break;
case "Fire":
if (context.phase == InputActionPhase.Performed)
print("开火了");
break;
case "Look":
print(context.ReadValue<Vector2>());
break;
}
}
#endregion
}