Unity中的新输入系统

Tulenber 5 June, 2020 ⸱ Intermediate ⸱ 8 min ⸱ 2019.3.15f1 ⸱

不久前,Unity推出了一个新的输入系统,这意味着现在应该仔细研究一下。

Unity不仅是一个积极开发的产品,而且还是一个变化很大的产品。新的渲染管道,UIElement和新的输入系统-这些都是最近的更改,必须使引擎更快,更灵活和更友好。历史上有很多例子,当公司在其产品中进行大型系统的重构时,这种变化的结果既是开发方面的新成功,也是崩溃的结果。抛开对此主题的悲伤想法,我们将看到新系统与旧系统有何不同。

世代相传

在Unity世界中,新的控制系统是一个非常引人注目的事件,社区对此表示了极大的热情,通常说当前版本不方便。制造商公司对此表示赞同,并指出旧系统是在添加大量受支持设备之前开发的,而不是最初为之设计的。因此,Internet包含大量的评论,这些评论通常显示新的动作资产的基本窗口的配置,您可以通过三个水平放置的大型设置块立即识别出它。我们将尝试朝相反的方向发展,首先,我们将研究新系统的基本要素,然后再转向更高的要素。

文献资料

对于这样的新程序包,New Input System提供了很好的文档,其中始终包含问题的答案,因此,我将立即为其提供链接,包括由于存在迁移之前必须考虑的限制。另外,请查看答案部分。这将为您的第一步做好充分的准备。

设定

由于带有新控制系统的软件包已发布,因此可以通过在软件包管理器中搜索名称Input System轻松找到它
Package Manager

在安装过程中,系统会通知您您的本机平台后端已关闭,并且在您失去对当前API的访问权限而切换到该平台之前,它将无法工作
Warning

尚不清楚他们为什么要吓f脆弱的头脑,因为可以在设置中一次打开两个系统Edit > Project settings… > Player > Other Settings > Active Input Handling*。因此,您如何回答有关系统切换的问题并不是很重要,您可以立即将后端更改为适合您的任何值。^_^
Settings

样品

安装该软件包后,您将可以使用新系统的大量示例集,其中包含您需要的所有内容,从简单的案例到更高级的主题,例如将控件添加到智能手机屏幕或在运行时重新配置控件。 Samples

建筑

该系统是如此广泛,以至于考虑其所有设置都是很成问题的,并且没有必要。该文档涵盖了开始所需的所有要点。

如果我们简要地描述该体系结构,那么它包含三个层次:

  • 本机后端-由当前平台提供,不属于新输入系统
  • 低层-以事件和原始数据的形式与后端交换信息,并且高度致力于通过内存操作和性能进行优化
  • 高层-以便于配置和使用的方式表示底层数据

另外,值得注意的是,新系统完全基于事件,并积极鼓励我们使用事件。

Input.GetMouseButtonDown(0)

我认为在开发初期或测试新机制时没有多少人设置控件,所以我想知道的第一件事是如何从代码中捕获常规的鼠标单击。在新系统中,对Input.GetMouseButtonDown(0)的调用变成了Mouse.current.leftButton.wasPressedThisFrame。 如您所见,字符数略有增加。另一方面,现在您可以忘记左键的索引,并且如果IDE中的自动完成功能可以理解您想要的内容,则差异将很小。使用相同的方法来访问键盘,例如,释放键盘Keyboard.current.spaceKey.wasReleasedThisFrame上的空格键。

InputAction

使用直接访问按钮不是使用新系统的主要方法。其中的基本概念是InputAction类型的对象。它是对事件源(按钮,操纵杆等)的抽象,它提供有关事件状态(无论是按下按钮还是操纵杆的方向)的数据,并借助事件通知它们的更改。最好将它们视为逻辑元素(跳跃或射击),而不要附加到诸如按键压力之类的物理属性上。

添加到组件的InputAction的示例视图:
Input action

InputAction设置提供以下参数的选择:
Action Settings

动作类型可以是三种类型:

  • Value-标准类型,用于任何输入,持续监视设备状态
  • Button-与Value的不同之处在于,它只能与按钮关联,并用于跟踪状态变化
  • Pass-Through-与其他类型不同,不使用开始执行取消的方案(事件的主要类型)并且始终处于执行状态,因此可以方便地处理来自多个事件源的所有数据

Control Type-描述设备提供的数据类型,例如,在使用摇杆的情况下,您可以获得Vector2结构形式的数据。

Interactions-提供自定义特定动作的功能,例如长按或多次单击。

Processors-在将数据分发给逻辑之前添加对来自控制器的数据的后处理,例如,标准化控制器上的操纵杆方向矢量。

对物理设备的访问取决于所选设置,因此它们可以提供所需的数据。例如,鼠标按钮只能处理单击,并且在选择以矢量的形式提供数据的情况下,不能用作监视的输入设备。

Bindings

另外,还有几种复合设备。例如,移动方向可以以通过四个按钮(WSAD或其他组合)获得的矢量的形式呈现。如有必要,可以在您自己的设备上补充一组复合设备,有关更多信息,请参见文档

使用InputAction不需要任何其他实体,并且非常适合在组件中使用。不要忘记在创建时将其关闭,并且需要通过调用Enable()方法来单独启用它们。

Action Maps

Action Maps是多个InputAction的并集,后者负责游戏中的不同动作集。 假设在菜单中,您使用控制器上的操纵杆在不同的界面按钮之间移动,并且在游戏中,操纵杆负责角色的移动。

Control Schema

Control Schema是InputAction的抽象,它允许您根据所使用的物理设备为这些操作设置不同的触发器。假设通过WSAD按钮从键盘控制运动,而通过左操纵杆从控制器控制运动。

Action Asset

Action Asset是一种新型资产,负责InputAction,ActionMap和Control Schemes的全面配置。 在大多数其他评论中,它可以看作是由三个区块组成的大型面板。
Action Asset

包起来

整个新系统围绕着InputAction集,以及旨在与它们进行结构化工作的所有其他事物。结果,使用新系统有四种主要方法:

  • 直接访问设备数据-例如使用Mouse.current.leftButton.wasPressedThisFrame
  • 使用基本的InputAction
  • 从Action Asset生成带有一组InputAction的类,这大大简化了使用不同方案的复杂控制系统的配置
  • 通过PlayerInput对象使用Action Asset

如您所见,Action Asset绝不是自定义控件的先决条件,而只是简化了使用广泛而复杂的解决方案的工作。

控制绑定

在上一篇文章中,我们介绍了命令模式,该命令模式通常用于添加重新配置游戏中控件的功能。在新系统中使用这种方法将在InputAction上增加一层抽象,因为它们已经是逻辑元素。反过来,控件的更改不是很明显,而是通过具有可疑名称InputActionRebindingExtensions的类实现的。该主题的文档中有一个单独的项目,并且该软件包随附了一个相当复杂的示例,名为Rebinding UI。由于这是控制系统的基本要素,因此我们将在下面考虑其最小化实现。

实践

完全创建Action Asset的示例在Internet上非常普遍,因此没有必要再重复一次。因此,作为一个简单的示例,我们将魔术师的控件从以前的文章中更改为使用具有基本InputAction的新系统,并且还添加了重新配置控件的功能。

Implementation

  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
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
using UnityEngine;
using UnityEngine.InputSystem;

public class InputHandler : MonoBehaviour
{
    // 引用法师对象
    public Mage mage = null;

    // 控制系统要素
    public InputAction fireInputAction = null;
    public InputAction rebindFireInputAction = null;

    // 重新绑定操作对象
    private InputActionRebindingExtensions.RebindingOperation _rebindOperation;

    // IMGUI样式
    private readonly GUIStyle _infoStyle = new GUIStyle();

    // 在第一帧更新之前调用开始
    void Start()
    {
        // IMGUI样式设置
        _infoStyle.normal.textColor = Color.white;
        _infoStyle.alignment = TextAnchor.MiddleCenter;
    }

    // 法术动作
    private void FireInputActionOnStarted(InputAction.CallbackContext ctx)
    {
        mage.FireSpell();
    }

    // 控制重新绑定动作
    private void RebindFireAction(InputAction.CallbackContext ctx)
    {
        Debug.Log("Rebind");

        // 要重新绑定控件,必须禁用InputAction
        fireInputAction.Disable();

        // 清除重新绑定的对象,以防万一
        _rebindOperation?.Cancel();

        // 新的rebindin操作对象
        _rebindOperation = fireInputAction.PerformInteractiveRebinding()
            .OnCancel(
                // 取消情况
                operation =>
                {
                    // 处置方法,用于防止内存泄漏
                    _rebindOperation?.Dispose();
                    _rebindOperation = null;
                    // 退回InputAction
                    fireInputAction.Enable();
                })
            .OnComplete(
                operation =>
                {
                    // 处置方法,用于防止内存泄漏
                    _rebindOperation?.Dispose();
                    _rebindOperation = null;
                    // 退回InputAction
                    fireInputAction.Enable();
                });

        // 重新绑定操作开始
        _rebindOperation.Start();
    }

    private void OnGUI()
    {
        // 当前控件绑定信息
        GUI.Box(new Rect (10, 10, 200, 55), "Current binding");

        // 当前按钮绑定信息
        string labelText = fireInputAction?.GetBindingDisplayString(InputBinding.DisplayStringOptions.DontIncludeInteractions);
        if (_rebindOperation != null)
        {
            // 重新绑定进行中的信息
            labelText = "<Rebind>";
        }
        
        GUI.Label (new Rect (20, 35, 180, 20), labelText, _infoStyle);
    }

    // 启用InputActions,默认情况下禁用
    private void OnEnable()
    {
        fireInputAction.Enable();
        rebindFireInputAction.Enable();

        // 将listenear添加到拼写用法事件
        fireInputAction.started += FireInputActionOnStarted;
        // 将listenear添加到重新绑定事件
        rebindFireInputAction.started += RebindFireAction;
    }

    // 禁用InputActions
    private void OnDisable()
    {
        fireInputAction.Disable();
        rebindFireInputAction.Disable();

        // 删除拼写用法事件的侦听器
        fireInputAction.started -= FireInputActionOnStarted;
        // 删除重新绑定事件的侦听器
        rebindFireInputAction.started -= RebindFireAction;
    }
}

除了添加按钮外,对于InputAction的基本用法不需要​​任何其他配置。
Input Handler

Action Settings

结果

鼠标左键用于首次启动该咒语,第二次射击发生在将操作重新配置为使用f键盘按钮之后
Result

结论

最初,使用新系统会导致在某些组件上添加自定义编辑器,例如在我们有关Perlin Noise生成器的颜色编辑器的文章中。但是了解到这是当前方法的巨大变化,并且很快就会过渡到全新的API。可能会吓走大量功能和新组件,但是文档和示例对于第一个版本来说相当不错。除非当前的限制对您的项目来说不是什么大问题,否则所有这些都为快速潜水带来了希望。我希望本文为您阐明了使用新输入系统的基础知识。下次见!^_^


如果您喜欢这篇文章,可以为它提供支持



Privacy policyCookie policyTerms of service
Tulenber 2020