1 - 玩家输入入门
本文将初步介绍UE5中增强输入系统的相关概念,例如输入操作(Input Action)和输入映射上下文(Input Mapping Context)的概念,还会讨论如何通过增强输入系统来处理玩家输入,以及如何让摄像机绕玩家旋转。
增强输入系统
虚幻引擎5现在有两个输入系统:
虚幻4开始使用的 传统输入系统:详见虚幻引擎 4.27 文档;
作为插件使用的 增强输入系统:
虚幻引擎5(UE5)项目有时会需要更多高级的输入功能,例如复杂的输入处理,或在运行时重新映射输入按键。增强输入(Enhanced Input) 为开发人员提供了这类功能,并能向上兼容 虚幻引擎4(UE4)的默认输入系统。
此插件实现了多种功能,例如径向死区、同时按键、上下文输入和优先级安排,并且能够在基于 资产 的环境中,拓展对于原始输入数据的筛选和处理功能。
在这里我们使用增强输入系统,在实际使用之前,需要到“编辑”,“插件”中启用增强输入插件(Enhanced Input)。
输入操作
输入操作(Input Action)是增强输入系统和项目代码之间的通信链接,每个输入操作应该表示用户可以执行的某件事,例如“移动”、“蹲伏”、“开火”等。可以在蓝图或C++代码中添加输入监听器来监听输入操作的状态何时发生变化。
接下来看看细节页面中的 Action 项:
首先是值类型(Value Type),它包括下列项:
- 数字(bool):用于具有二进制状态的输入操作。例如跳跃操作,玩家要么按下它要么不会按。
- Axis1D (float):用于在一维中具有标量状态的输入操作,例如在开车时的踩油门操作,可以通过轻推/重推手柄来控制踩油门的程度。
- Axis2D (Vector2D):用于在二维中具有标量状态的输入操作,例如使用两个轴(前向轴和横向轴)的移动角色操作。
- Axis3D(Vector):用于在三维中具有标量状态的输入操作,不常用。
然后是触发器(Trigger),用于指定执行此输入操作的关键事件,可组合的事件如下:
- 弦操作 Chorded Action:只要另一个指定的输入操作被触发,那么该输入操作也会被触发。
- 按下 Down:当按键超过阈值,每一帧都会触发此操作。
- 按住 Hold:当按键持续时间超过阈值,此操作被触发。可以指定只触发一次还是每帧都触发。
- 按住并松开 Hold and Release:当按键持续时间超过阈值,且按键松开后,此操作被触发。
- 已按下 Pressed:当按键超过阈值,直到松开前只触发一次操作。
- 脉冲 Pulse:当按键超过阈值,输入操作会以指定的时间间隔触发。可以指定首次脉冲是否触发,以及触发的脉冲次数。
- 已松开 Released:按键松开时间超过阈值时,该操作被触发。
- 点按 Tap:按键和松键的时间间隔在指定时间内,且按键超过阈值时,该操作被触发。
最后是修改器(Modifier),用于指定修改如何此输入操作的输入,修改器如下:
- 盲区 Dead Zone:如果低于下阈值,结果被修改为0;如果高于上阈值,结果被修改为1.
- 视野缩放 Fov Scaling:输入结果将随Fov的缩放而缩放。
- 取反 Negate:输入结果将被反转(例如1会变成-1)。
- 响应曲线-指数 Response Curve-Exponential:对输入结果应用指数曲线。
- 响应曲线-自定义 Response Curve-User Defined:对输入结果应用用户自定义曲线。
- 标量 Scalar:对输入结果在每个轴上按指定值缩放。
- 平滑 Smooth:输入结果将在多个帧之间平滑处理(插值)。
- 拌合输入轴值 Swizzle Input Axis Values:输入结果的轴顺序将会被切换。
- 转换为世界空间 To World Space:输入结果的轴会被转换为世界空间。
输入映射上下文
输入映射上下文(Input Mapping Contexts)是输入操作的集合,表示玩家可以处于的特定上下文(如走路时,开车时)。它们描述了给定输入操作的触发规则。
细节页面中的 Mapping 项如下,可见它组织了上面提到的输入操作,并为输入操作指定输入方式:
输入映射上下文的触发器和修改器与输入操作的大致相同,这里不做赘述。
处理玩家输入
跳跃操作
接下来看看增强输入系统是如何处理玩家输入的,例如玩家按下空格后角色就会跳跃:
- 硬件输入:玩家按下空格键,游戏引擎会监听这个按键事件。
- PlayerInput类:将按下/松开空格键翻译为一个输入操作,如果刚好有对应的输入操作,它将通知所有监听此操作的类(是否刚刚按下、松开或更新),在这里是通知跳跃操作被触发了。
- PlayerController类:是第一个接收到按键事件的类。
- Pawn类:只要该类(及其子类)被玩家控制器类拥有,就能监听按键事件。
接下来实际操作试试,这里将准备一个玩家角色类,然后将其作为父类给蓝图类使用。
创建好玩家角色类后,开始给蓝图准备要绑定的输入操作和输入映射上下文属性:
// MyCharacter.h
// 该角色的输入映射上下文
UPROPERTY(EditAnywhere, Category = Input)
UInputMappingContext* IC_Character;
// 该角色的跳跃输入操作
UPROPERTY(EditAnywhere, Category = Input)
UInputAction* IA_Jump;
接下来需要在MyCharacter.cpp
中绑定监听输入操作:
// MyCharacter.cpp
// Called to bind functionality to input
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
// 强转为增强输入组件
UEnhancedInputComponent* EnhancedPlayerInputComponent = Cast<UEnhancedInputComponent>(PlayerInputComponent);
if (EnhancedPlayerInputComponent != nullptr)
{
// 添加输入映射上下文
APlayerController* PlayerController = Cast<APlayerController>(GetController());
if (PlayerController != nullptr)
{
UEnhancedInputLocalPlayerSubsystem* EnhancedSubsystem =
ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer());
if (EnhancedSubsystem != nullptr)
{
EnhancedSubsystem->AddMappingContext(IC_Character, 1);
}
}
// TODO: 还能使用委托(Delegates)监听输入操作
// 绑定输入操作监听
EnhancedPlayerInputComponent->BindAction(IA_Jump, ETriggerEvent::Started, this, &ACharacter::Jump);
EnhancedPlayerInputComponent->BindAction(IA_Jump, ETriggerEvent::Completed, this, &ACharacter::StopJumping);
}
}
这段代码首先给增强输入系统添加输入映射上下文,通过EnhancedSubSystem->AddMappingContext()
实现,该函数的参数解释如下:
UInputMappingContext* MappingContext
:想要激活的输入映射上下文,这里是IC_Character
属性。int32 Priority
:输入映射情景(们)的优先级,这里是1。
然后还添加了监听输入操作的逻辑,通过EnhancedPlayerInputComponent->BindAction()
实现,该函数的参数解释如下:
UInputAction* Action
:要监听的输入操作,这里是IA_Jump
。ETriggerEvent TriggerEvent
:触发监听的输入事件,这里选择在触发计算开始时的ETriggerEvent::Started
和在出发计算完成后的ETriggerEvent::Completed
。UserClass* Object
:回调函数被调用的对象,这里是this
。HANDLER_SIG::TUObjectMethodDelegate<UserClass>::FMethodPtrFunc
:输入发生时要调用的函数指针,这里分别是&ACharacter::Jump
和&ACharacter::StopJumping
。
别忘了创建并设定对应的资产:
然后就能实现角色的跳跃了。
摄像机环绕操作
和跳跃操作类似,首先是输入操作IA_Look
:
然后是输入映射上下文IC_Character
的补充:
对于Y轴输入要注意,首先要把轴次序修改为YXZ,然后取反。
接下来是C++代码逻辑:
// MyCharacter.h
// 该角色的摄像机移动操作
UPROPERTY(EditAnywhere, Category = Input)
UInputAction* IA_Look;
protected:
// 角色摄像机的移动
void Look(const FInputActionValue& Value);
// MyCharacter.cpp
void AMyThirdPersonChar::Look(const FInputActionValue& Value)
{
FVector2D InputValue = Value.Get<FVector2D>();
AddControllerYawInput(InputValue.X);
AddControllerPitchInput(InputValue.Y);
}
void AMyThirdPersonChar::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
...
EnhancedPlayerInputComponent->BindAction(IA_Look, ETriggerEvent::Triggered, this, &AMyThirdPersonChar::Look);
...
}
其中AddControllerYawInput()
和AddControllerPitchInput()
分别负责围绕Z轴(向左和向右转动)和Y轴(向上和向下看)的旋转输入。
这样就实现了围绕角色转动的摄像机。
参考资料
- 中文翻译:《UE5 C++ 游戏开发完全学习教程》
- 英文原版:《Elevating Game Experiences with UE5》
- 虚幻引擎中的增强输入 | 虚幻引擎 5.5 文档 | Epic Developer Community (epicgames.com)