增强输入

使用Enhanced Input插件来读取和解译用户输入

Windows
MacOS
Linux

对于需要更多高级输入功能的项目,例如复杂的输入处理或运行时控制重新映射,实验性的 Enhanced Input插件(Enhanced Input Plugin) 让开发人员能够轻松升级路径,并且可以向后兼容引擎的默认输入系统。此插件实施了多种功能,例如径向死区、弹奏动作、上下文输入和优先级安排,并且能够在基于资产的环境中扩展你自己的原始输入数据过滤和处理功能。

入门指南

要将你的项目配置为使用Enhanced Input,请启用Enhanced Input插件。通过在编辑器中打开 编辑(Edit) 下拉菜单并选择 插件(Plugins),可以启用此插件。在插件列表的 输入(Input) 部分中,找到Enhanced Input插件并启用,然后重启编辑器。

EnhancedInputPlugin.png

插件将在你重启编辑器后激活。

编辑器重启之后,你就可以将项目设置为使用Enhanced Input插件类,而不是默认的UE4输入处理程序。转到 编辑(Edit) 下拉菜单,然后选择 项目设置(Project Settings)。在其中找到 输入(Input) 部分(在 引擎(Engine) 标题栏下),然后找到 默认类(Default Classes) 设置。这些设置最初包含标准的 PlayerInputInputComponent 类。

EnhancedInputDefaultClasses.png

要使用Enhanced Input,需要将这些设置分别更改为 EnhancedPlayerInputEnhancedInputComponent

EnhancedInputDefaultClasses2.png

核心概念

Enhanced Input系统具有四个主要概念:

  • 输入操作(Input Actions) 是Enhanced Input系统和你的项目代码之间的通信链接。输入操作可以是交互角色可能做出的任何动作,例如跳跃或开门,但也可以用于指示用户输入状态,例如按住按钮可以将行走动作更改为奔跑动作。输入操作独立于原始输入;输入操作与触发输入操作的特定输入无关,但知道其当前状态并可以在最多三个独立的浮点轴上报告输入值。例如,"拾取道具"操作可能仅需要一个开/关状态,用于指示用户是否在尝试捡起某个东西,而"行走"操作可能需要两个轴来描述用户尝试行走的方向和速度。

  • 输入映射向下文(Input Mapping Contexts) 将用户输入映射到操作,并可以动态地为每个用户添加、移除或安排优先次序。你可以通过本地玩家的 Enhanced Input本地玩家子系统(Enhanced Input Local Player Subsystem) 将一个或多个上下文应用到本地玩家,并安排它们的优先次序,避免多个操作由于尝试使用同一输入而发生冲突。此问题的常见示例是,当角色在世界中四处行走时,一个按钮可以开门,或者在查看角色的背包时,这个按钮又可以选择道具。无论角色何时打开背包,你都可以添加"选择道具"输入映射上下文,使其优先于"开门"上下文,然后在角色关闭背包时,移除"选择道具"上下文。这样可以确保根据角色的环境来正确解译用户的输入,不再需要在输入处理层编写代码来区分门和背包系统。

  • 修饰符(Modifiers) 调整来自用户设备的原始输入的值。输入映射上下文可以具有与输入操作的每个原始输入关联的任意数量的修饰符。常见修饰符包括死区、多个帧上的输入平滑处理、将输入矢量从本地转换到世界空间,以及插件中包含的一些其他修饰符;开发人员还可以创建他们自己的修饰符。

  • 触发器(Triggers) 使用后期修饰符输入值或其他输入操作的输出大小来确定是否应该激活输入操作。输入映射上下文中的任何输入操作对于每个输入都具有一个或多个触发器。例如,为了拍摄照片,可能需要用户在用于瞄准摄像机的单独输入操作处于激活状态时按住鼠标左键约0.25秒。

通过综合利用这些概念,开发人员可以快速设置从简单到复杂的各种输入系统并调整这些系统,而不需要更改项目代码。

输入操作

输入操作是系统和你的项目代码之间的连接。通过在 上下文浏览器(Context Browser) 中右键点击并展开 输入(Input) 选项,然后选择 输入操作(Input Actions),可以创建输入操作。要触发输入操作,必须将其包含在输入映射上下文中,并将该输入映射上下文添加到本地玩家的 Enhanced Input本地玩家子系统(Enhanced Input Local Player Subsystem)

EnhancedInput_CreateAsset.png

要使你的Pawn类响应所触发的输入操作,你必须将其绑定到 SetupPlayerInputComponent 中的相应类型的 触发器事件(Trigger Event)。以下示例代码重载 SetupPlayerInputComponent,以将两个输入操作(MyInputActionMyOtherInputAction)绑定到处理程序函数:

// 确保我们正在使用 UEnhancedInputComponent;如果未使用,表明项目未正确配置。
if (UEnhancedInputComponent* PlayerEnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent))
{
    // 有多种方式可以将UInputAction*绑定到处理程序函数和可能有关的多种类型的ETriggerEvent。

    // 当MyInputAction启动时,这会在更新函数上调用处理程序函数,例如在按操作按钮时。
    if (MyInputAction)
    {
        PlayerEnhancedInputComponent->BindAction(MyInputAction, ETriggerEvent::Started, this, &AMyPawn::MyInputHandlerFunction);
    }

    // 当满足输入条件时,例如在按住某个动作键时,这会在每个更新函数上按名称调用处理程序函数(UFUNCTION)。
    if (MyOtherInputAction)
    {
        PlayerEnhancedInputComponent->BindAction(MyOtherInputAction, ETriggerEvent::Triggered, this, TEXT("MyOtherInputHandlerFunction"));
    }
}

使用Enhanced Input插件绑定输入操作将会替换内置输入系统的操作和轴绑定;如果你正在使用Enhanced Input插件,则应该仅绑定输入操作。

在绑定输入操作时,可以在四种不同的处理程序函数签名之间进行选择,如下所示:

返回类型

参数

用法说明

void

()

适用于简单案例,这种案例不需要来自Enhanced Input系统的任何额外信息

void

(const FInputActionValue& ActionValue)

提供对输入操作当前值的访问权限

void

(const FInputActionInstance& ActionInstance)

在按名称动态绑定到UFunction时使用的签名;参数可选

此绑定类型的主要目的是向蓝图脚本公开输入操作。由于Enhanced Input插件不会自动完成此操作,因此操作人员很少需要使用此绑定方法。

void

(FInputActionValue ActionValue, float ElapsedTime, float TriggeredTime)

输入操作具有内置的事件,可以将其公开给蓝图脚本;在向蓝图脚本开发人员提供对输入操作事件的访问权限时,C++开发人员不必创建传递函数。

典型的处理程序函数可能采用以下形式:

void AMyPawn::MyFirstAction(const FInputActionValue& Value)
{
    // 用于确认处理程序函数正在运行的调试日志输出。
    UE_LOG(LogTemp, Warning, TEXT("%s called with Input Action Value %s (magnitude %f)"), TEXT(__FUNCTION__), *Value.ToString(), Value.GetMagnitude());
    // 使用GetType()函数来确定Value的类型,使用索引在0和2之间的[]运算符来访问其数据。
}

对于大部分用例,建议使用 void (const FInputActionValue&) 签名。

将输入操作绑定到处理程序函数可以让Pawn根据函数的具体触发方式来响应这些函数。对于按按钮时仅发生一次的操作,最常见的触发器类型可能是 Started,对于按住输入时每一帧都发生的持续操作,触发器类型可能是 Triggered,但是你可以在ETriggerEventETriggerEvent的API参考页上查看完整列表。

输入映射上下文

输入映射上下文介绍用于触发一个或多个输入操作的规则。它的基本结构是一个在顶层具有输入操作列表的层级。输入操作层下面是一个用户输入列表,该列表可以触发各个操作,例如键、按钮和动作轴。底层包含各个用户输入的输入触发器和输入修饰符列表,该列表可以用于确定如何过滤或处理输入的原始值,以及它必须满足哪些限制才能在其层级的顶层驱动输入操作。任何输入都可以具有多个输入修饰符和输入触发器。这些修饰符和触发器将按照其在你创建的列表中的顺序进行求值;这对于输入修饰符尤其重要,因为修饰符使用每个步骤的输出作为下个步骤的输入。

要创建输入映射上下文,请右键点击 上下文浏览器(Context Browser) ,展开 输入(Input) 选项,然后选择 输入映射上下文(Input Mapping Context)

EnhancedInput_CreateAsset.png

使用所有相关的输入操作填充你的输入映射上下文。对于简单的项目,你可以将所有的输入操作放入单个输入映射上下文中。较复杂的项目最好可以使用多个输入映射上下文工作,因为本地玩家可以同时具有多个活动的输入映射上下文。例如,一个可以游泳、行走和驾驶载具的角色可能具有多个输入映射上下文;一个上下文用于始终可用且始终映射到相同用户输入的常见操作,另一个用于行程中每个单独的模式。开发人员随后可以将与载具相关的输入操作放入单独的输入映射上下文中,而该上下文随后在进入载具时添加到本地玩家,并在退出载具时从本地玩家中移除。这样做可以确保不会运行不恰当的输入操作(并且不会浪费CPU周期),并避免互斥的输入映射上下文将某个用户输入用于不同的输入操作而导致发输入冲突,从而减少漏洞。如需更多详细信息,请参见修饰符触发器中的相应部分。

InputMappingContext_Hierarchy.png

此输入映射上下文显示用于奔跑的输入操作,该输入操作可以通过多个输入来激活,包括游戏手柄的左控制杆偏转,将两个轴组合为单个输入。。该输入的原始值将经过"死区"输入修饰符,生成的值将发送到"按住"输入触发器来驱动"RunAction"输入操作。

InputMappingContext_Key.png

下拉列表中有大量的输入绑定可用。要更加快速地选择你的输入绑定,请按下拉列表左侧的小按钮,然后按你要绑定的键或按钮。

InputMappingContext.png

这个简单的输入映射上下文支持用于奔跑和跳跃的输入操作。

填充输入映射上下文之后,就可以将其添加到与Pawn的玩家控制器关联的本地玩家。通过重载 PawnClientRestart 函数和添加代码块可以完成此目标,如下所示:

// 确保我们具有有效的玩家控制器。
if (APlayerController* PC = Cast<APlayerController>(GetController()))
{
    // 从与我们的玩家控制器相关的本地玩家获取Enhanced Input本地玩家子系统。
    if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
    {
        // PawnClientRestart在Actor的生命周期中可以运行多次,因此首先要清除任何残留的映射。
        Subsystem->ClearAllMappings();

        // 添加每个映射上下文及其优先级值。较高的值优先于较低的值。
        Subsystem->AddMappingContext(MyInputMappingContext, MyInt32Priority);
    }
}

添加你的输入映射上下文之后,你的Pawn就可以响应你在 SetupPlayerInputComponent 中绑定的任何输入操作事件,或响应蓝图脚本用户已经设置的任何输入操作事件。如果游戏期间发生事件,需要更改可用输入映射上下文集,则你可以使用 ClearAllMappingsAddMappingContextRemoveMappingContext 来动态更新可用命令集。如需更多信息,请查看IEnhancedInputSubsystemInterfaceIEnhancedInputSubsystemInterfaceAPI参考页面。

输入修饰符

输入修饰符是预处理器,能够修改UE4接收的原始输入值,然后再将其发送到输入触发器上。 Enhanced Input插件随附多种输入修饰符,可以执行各种任务,例如更改轴顺序、实施"死区"、将轴输入转换为世界空间以及其他功能。每个与输入映射上下文中的输入操作关联的输入都将经历用户定义的一系列输入修饰符,然后再继续进入该输入的输入触发器。输入修饰符按照列示的顺序进行应用,每个输入修饰符的输出值都会成为下一个修饰符的输入值。

如需查看Enhanced Input插件中包含的输入修饰符的完整列表,请查看UInputModifierUInputModifierAPI参考页面。如果你的项目需要尚不存在的输入修饰符,可以创建你自己的 UInputModifier 类。

方向输入

一个可以良好展示输入修饰符用途的示例是,使用单一输入操作实现二维方向输入。使用鼠标或游戏手柄的虚拟摇杆时,读取二维移动是很简单的事情,只需创建支持至少两个轴的输入操作并将相应的输入添加到输入映射上下文。但是,如果你还想要支持来自一维源的输入,例如键盘的方向键或常用的"WASD"配置,则可通过应用正确的输入修饰符来实现。具体而言,应用"负(Negate)"可以将某些键注册为负值,而"交换输入轴值(Swizzle Input Axis Values)"可以将某些键注册为Y轴,而不是默认的X轴值。为了实现此目标,请按照以下方式配置你的输入:

字母键

方向键

需要的输入解译

需要的输入修饰符

W

向上

正Y轴

交换输入轴值(Swizzle Input Axis Values)(YXZ或ZXY)

A

向左

负X轴

负(Negate)

S

向下

负Y轴

负(Negate)

交换输入轴值(Swizzle Input Axis Values)(YXZ或ZXY)

D

向右

正X轴

(无)

InterpretingWASD.png

这种解译方向键或"WASD"键的方式可以将一维输入映射到二维输入操作。

由于每个键都报告一维正值,此值将始终占据X轴并且将在任何给定的更新函数上都具有值0.0或1.0。通过为向左或向下输入设置负值,并切换轴的顺序使输入的X轴值移至Y轴以进行向上或向下输入,你可以使用输入修饰符将一组一维输入解译为单个二维输入值。

输入触发器

输入触发器确定用户输入在经历过输入修饰符的可选列表之后是否应该在其输入映射上下文中激活相应的输入操作。大部分输入触发器都会分析输入本身,检查最小动作值并验证各种模式,例如短暂点击、长时间按住或典型的"按下"或"释放"事件。此规则的一个例外是"弹奏动作"输入触发器,该触发器要求触发另一个输入操作。默认情况下,输入上的任何用户活动都会在每个更新函数上触发。

如需查看Enhanced Input插件中包含的输入触发器的完整列表,请查看UInputTriggerUInputTriggerAPI参考页面。如果你需要Enhanced Input插件未提供的输入触发器,那么可以创建自己的 UInputTrigger 类。

欢迎帮助改进虚幻引擎文档!请告诉我们该如何更好地为您服务。
填写问卷调查
取消