注意: 新的输入法系统需要 Unity 2019.4+ 和 .NET 4 运行时。它不适用于 .NET 3.5 的项目。
前言
在游戏开发中,良好的输入系统是确保游戏玩家与游戏世界交互流畅的关键之一。长期以来,Unity 的老版输入系统 InputManager 在处理输入方面发挥了重要作用。然而,随着游戏开发技术的不断发展和用户需求的日益增加,Unity 推出了一种全新的输入系统:Input System。
Unity 的 Input System 是 Unity 提供的一种新的输入系统,相较于旧版的 InputManager,它具有以下优点:
-
灵活性和可配置性: Input System 提供了更灵活和可配置的输入管理方案。你可以通过代码或者通过可视化工具来配置输入,而不是像旧版的 InputManager 那样需要在编辑器中手动添加和管理输入。
-
跨平台支持: Input System 提供了更好的跨平台支持,可以在不同平台上统一处理输入,减少了针对不同平台的输入处理代码的编写。
-
输入处理性能优化: Input System 的设计更加高效,能够更好地管理输入事件的处理,降低了输入处理的性能开销,特别是在大量输入事件的情况下。
-
多种输入设备支持: Input System 对多种输入设备(如键盘、鼠标、手柄、触摸屏等)提供了更好的支持,可以更方便地处理不同输入设备的输入。
-
可扩展性: Input System 的设计更加模块化和可扩展,可以方便地扩展新的输入设备或者自定义输入处理逻辑,满足不同项目的需求。
总的来说,Input System 是 Unity 提供的一种更先进、更灵活、更高效的输入管理方案,能够帮助开发者更方便地处理输入,并提升游戏的性能和跨平台兼容性。
安装
导航栏 -> Window -> Package Manager,选择 Unity Registry 在列表中找到 Input System 点击 Install 安装
新旧输入系统切换
Unity 默认会同时启用旧版和新版输入系统,你可以在 Player settings 中(Edit -> Project Settings -> Player ->Active Input Handling) 找到相应的设置。可以随时修改这里的设置,这样做依然会重启编辑器。
基础使用
快速监听某个按键按下抬起操作
void Update()
{
// 检查空格键是否在这个帧被按下
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
Debug.Log("Space key was pressed");
}
// 检查空格键是否在这个帧被释放
if (Keyboard.current.spaceKey.wasReleasedThisFrame)
{
Debug.Log("Space key was released");
}
// 检查左鼠标键是否在这个帧被按下
if (Mouse.current.leftButton.wasPressedThisFrame)
{
Debug.Log("Left mouse button was pressed");
}
// 检查左鼠标键是否在这个帧被释放
if (Mouse.current.leftButton.wasReleasedThisFrame)
{
Debug.Log("Left mouse button was released");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
使用可视化编辑器来建立映射
Project -> Create -> Input Actions
新建 Input Actions 给其命名(名称无所谓),我这里命名为 Test Input Controls 完成后,选中该文件勾选 Generate C# Class点击 Apply 后 Unity 会为我们生成一个 Action 的包装类,方便后续在代码中引用。
Action Map
可以理解为一个组织和管理输入动作的一种方式。通过将相关的输入动作放在同一个Action Map中,可以更好地管理输入逻辑。例如,可以将所有与玩家移动相关的输入动作放在一个叫做"Movement"的Action Map中。
Action
一个具体的输入动作,比如按键按下、摇杆移动等。
生成结束点击 Edit asset 创建第一个 Action Map 并将其命名为 Player 并将 Actions 列表生成的 Action 重命名为 Fire 。
选中 < No Binding > 给 Fire Action 映射对应的按键(按键可以自定义,笔者映射的按键为键盘的 K 键)
也可以绑定多个按键对应不同的操作设备,我这里映射的第二个按键为鼠标左键
完成上述操作后点击 Save Asset 保存当前映射表,这样做可以绑定多个物理输入得到的输入值也只会影响同引用的 Action 对象。
通过代码监听映射表中的按键
创建测试脚本 TestInputSystem (命名可随意),我们需要使用之前的 TestInputControls ,通过监听 started 和 canceled 实现按键按下抬起操作。具体可参考下述代码
// 输入控制类的实例
private TestInputControls InputControls;
void OnEnable()
{
InputControls = new TestInputControls(); // 创建输入控制实例
InputControls.Player.Fire.started += OnFireDown; // 注册开火开始动作的回调
InputControls.Player.Fire.canceled += OnFireUp; // 注册开火结束动作的回调
InputControls.Enable(); // 启用输入控制
}
//当开火动作被触发时调用此方法。
private void OnFireDown(InputAction.CallbackContext Obj)
{
Debug.Log("Jump!" + Obj.phase);//输出按下类型 started canceled performed
Debug.Log($"Fire Down | KeyName:{Obj.control.name}"); // 输出"Fire Down"到控制台
}
//当开火动作释放时调用此方法。
private void OnFireUp(InputAction.CallbackContext Obj)
{
Debug.Log($"Fire Up | KeyName:{Obj.control.name}"); // 输出"Fire Up"到控制台
}
//主要用于移除输入动作的回调函数,并禁用输入控制。
private void OnDisable()
{
InputControls.Player.Fire.started -= OnFireDown; // 移除开火开始事件的监听
InputControls.Player.Fire.canceled -= OnFireUp; // 移除开火结束事件的监听
InputControls.Disable(); // 禁用输入控制
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
测试效果
可以看到,我们使用一套代码就可以同时监听键盘和鼠标的输入
按下抬起有了,要想实现长按也很简单。选中 TestInputControls 点击 Edit asset 在 Action Properties 一栏点击 Interactions 后方的+号添加 Hold
Hold:按下并按住至少设定的持续时间(默认为defaultHoldTime),则执行动作。(长按执行操作)
MultiTap:需要多次轻击(在tapTime内按下并释放),每次轻击之间的间隔不超过tapDelay秒(双击或多击)
Press:根据按钮的按下和释放顺序来触发特定的操作(例如:在按下按钮后执行某个动作或在释放按钮时执行某个操作)
SlowTap:按下并按住控件一段时间后释放时执行操作(长按释放后执行操作) Tap:按下并按住小段时间内释放执行操作(点击)
添加完 Hold 后,看一下它的两个变量。如果默认值不能满足你的需求,取消勾选 Default 可自定义变量值。修改 Hold Time 变量一般即可满足需求
Press Point:按下按键这个阈值才能被认为是按下(笔者理解的是按压力度)
Hold Time:按下并按住按键保持的时间(以秒为单位)。
还是之前的代码在此基础上增加了长按监听的代码,具体参考下述代码
// 输入控制类的实例
private TestInputControls InputControls;
void OnEnable()
{
InputControls = new TestInputControls(); // 创建输入控制实例
InputControls.Player.Fire.started += OnFireDown; // 注册开火开始动作的回调
InputControls.Player.Fire.performed += OnLongPress; // 注册长按动作的回调
InputControls.Player.Fire.canceled += OnFireUp; // 注册开火结束动作的回调
InputControls.Enable(); // 启用输入控制
}
//当开火动作被触发时调用此方法。
private void OnFireDown(InputAction.CallbackContext Obj)
{
Debug.Log($"Fire Down | KeyName:{Obj.control.name}"); // 输出"Fire Down"到控制台
}
//当开火动作持续时调用的方法。
private void OnLongPress(InputAction.CallbackContext Obj)
{
Debug.Log($"Fire Long Press | KeyName:{Obj.control.name},持续时间{Obj.duration}"); // 输出动作持续时间
}
//当开火动作释放时调用此方法。
private void OnFireUp(InputAction.CallbackContext Obj)
{
Debug.Log($"Fire Up | KeyName:{Obj.control.name}"); // 输出"Fire Up"到控制台
}
//主要用于移除输入动作的回调函数,并禁用输入控制。
private void OnDisable()
{
InputControls.Player.Fire.started -= OnFireDown; // 移除开火开始事件的监听
InputControls.Player.Fire.performed -= OnLongPress; // 移除长按事件的监听
InputControls.Player.Fire.canceled -= OnFireUp; // 移除开火结束事件的监听
InputControls.Disable(); // 禁用输入控制
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
经过上述步骤,我们学习到了新版 InputSystem 中的三个最基本的按键触发(按下、抬起、长按)。
实战
快速创建Input Actions映射
新增Player Input组件,点击创建新的输入系统,生成之后就可以删除Player Input组件了
会自动给我们创建好一些必备输入参数,比如移动
代码调用,点击自动生成代码
移动
新增PlayerController ,代码调用
public class PlayerController : MonoBehaviour
{
public PlayerInputControl inputSystem;
public Vector2 inputDirection;
public float speed;
private Rigidbody2D rb;
private void Awake()
{
// 初始化输入控制
inputSystem = new PlayerInputControl();
rb = GetComponent<Rigidbody2D>();
}
private void OnEnable()
{
// 启用输入控制
inputSystem.Enable();
}
private void OnDisable()
{
// 禁用输入控制
inputSystem.Disable();
}
private void Update()
{
// 获取输入方向
inputDirection = inputSystem.Player.Move.ReadValue<Vector2>();
}
private void FixedUpdate()
{
Move();
}
//移动角色
private void Move()
{
// 根据输入方向移动角色
rb.velocity = new Vector2(inputDirection.x * speed * Time.deltaTime, rb.velocity.y);
// 根据输入方向翻转角色
if (inputDirection.x < 0)
{
transform.localScale = new Vector3(-Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);
}
else if (inputDirection.x > 0)
{
transform.localScale = new Vector3(Mathf.Abs(transform.localScale.x), transform.localScale.y, transform.localScale.z);
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
配置
效果
跳跃
键盘
手柄,如果有的话
修改PlayerController
using UnityEngine.InputSystem;
public float jumpForce;
private void Awake()
{
// 初始化输入控制
inputSystem = new PlayerInputControl();
rb = GetComponent<Rigidbody2D>();
inputSystem.Player.Jump.started += Jump;
}
//跳跃
private void Jump(InputAction.CallbackContext context){
rb.AddForce(transform.up * jumpForce, ForceMode2D.Impulse);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
效果
移动端支持
虚拟摇杆
虚拟摇杆input system已经帮我们做好了一个非常好的工具,模拟左侧操作杆,只需要挂载On-Screen Stick脚本即可
运行效果,没错就是这么简单,甚至你都不需要修改代码
虚拟按钮
绘制按钮UI
模拟不同的按钮
配置默认隐藏,开始游戏再显示
效果
区分不同设备的配置表(2024/07/02补充)
PC的按键勾选分类
手柄的按键勾选分类
把不同的设备按键绑定区分开
不同的输入系统
游戏时候可以用gameplay系统
而退出游戏时我们可以用UI输入系统
就比如我们进游戏选择菜单的时候用UI系统
我们玩游戏的时候就用gameplay系统
代码切换不同输入系统
# 切换操作映射
public void SwitchActionMap(InputActionMap actionMap)
{
parameter.inputSystem.Disable(); // 禁用当前的输入映射
actionMap.Enable(); // 启用新的输入映射
}
# 调用
SwitchActionMap(parameter.inputSystem.Player); // 切换到游戏操作的输入映射
SwitchActionMap(parameter.inputSystem.UI);//切换为UI输入
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
UI交互
InputSystem在UI上的应用
在创建canvas的同时
又创建了一个EventSystem
它原本是老版的输入系统
但是我们升级完InputSystem
新版的输入系统之后,它就会报错
我们把它别级为新版的输入系统
Actions Asset里面
默认给我们创建一个DefaultInputActions,绑定的按键和UI事件是对应的
UI的输入时间我们就用默认的就好了,原来的UI就不需要添加任何东西
鼠标滚轮滚动事件
参考
【文章】https://developer.unity.cn/projects/6602debfedbc2a001dcd1a82
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,以便我第一时间收到反馈,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~



评论记录:
回复评论: