目录
前言
前两章中我们添加了 AuraPlayerController 类用于控制角色的移动,Input Action 用于来接收键盘输入,并配以 Input Mapping Context 将输入映射为 x(前后)y (左右)坐标。
AuraPlayerController 中定义了 AuraContext 变量来绑定 Input Mapping Context 蓝图对象,并将其添加到增强输入本地玩家子系统(UEnhancedInputLocalPlayerSubsystem)中。这样我们就可以在 AuraPlayerControlller 中访问输入数据。
那么 AuraPlayerController 是如何获取这些输入数据的呢?答案是通过 Setup Player Input Component。
增强输入组件(Setup Player Input Component)
最一开始创建的 AuraCharacterBase 中默认是有 SetupPlayerInputComponet(UInputComponent* PlayerInputComponent) 方法,但是我们将其删除掉了,目的是为了统一在 AuraPlayerController 中实现这一功能。
在 AuraPlayerController.h 的 protected 部分添加 SetupInputComponent() 函数。
c
protected:
virtual void BeginPlay() override;
virtual void SetupInputComponent() override;
由于 Actor 类有一个 UInputComponent 成员变量,所以可以认为 AuraPlayerController 同样有一个 UInputComponent 成员变量。
但是我们之前讨论是使用增强输入本地玩家子系统,其输入组件为 UEnhancedInputComponent,所以需要将 UInputComponent 转为 UEnhancedInputComponent。在 SetupInputComponent() 方法中实现这一转化:
c
void AAuraPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(InputComponent);
}
上一章节中我们在 AuraPlayerController 中添加了一个 AuraContext 变量用以绑定 Input Mapping Context,同样也需要添加一个 UInputAction 来对应 Input Action。
c
private:
UPROPERTY(EditAnywhere, Category = "Input")
TObjectPtr<UInputMappingContext> AuraContext;
UPROPERTY(EditAnywhere, Category = "Input")
TObjectPtr<UInputAction> MoveAction;
MoveAction 会根据之前配置的 AuraContext 来将不同按键接收数据,但还需要添加一个方法来处理这些数据,在 AuraPlayerController 中添加 Move 方法:
c
private:
UPROPERTY(EditAnywhere, Category = "Input")
TObjectPtr<UInputMappingContext> AuraContext;
UPROPERTY(EditAnywhere, Category = "Input")
TObjectPtr<UInputAction> MoveAction;
void Move(const struct FInputActionValue& InputActionValue);
只是有了接收键盘输入的 Input Action 和 实现移动逻辑的 Move() 函数还不行,还需要将两者绑定起来,绑定后当按下 WASD 时才会调用该方法。增强输入组件(EnhancedInputComponent)提供了绑定两者的方法:
c
void AAuraPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(InputComponent);
// 绑定 Input Action 到 Move 函数
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AAuraPlayerController::Move);
}
Move() 方法的入参为 FInputActionValue 的地址引用,通过它可以获取输入键值,FInputActionValue 是一个结构体,其中不仅包含有 Axis2D 类型数据,还有 Axis1D、Axis3D,而我们实现的是俯视角类型游戏,所以只需要 Axis2D 类型数据。
从 FInputActionValue 中拿到 Axis2D 数据,并从中获取 x 轴,y 轴坐标值:定义一个 Axis2D 类型变量并通过 FInputActionValue 的模板函数 Get<>() 方法为其赋值:
c
const FVector2D InputAxisVector = InputActionValue.Get<FVector2D>();
const FRotator Rotation = GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); // 前后(x大于零表前,小于零表后)
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); // 左右(y大于零表示右,小于零表示左)
AddMovementInput() 函数可以为我们的角色控制器(APwan)根据 x,y 值来添加移动控制。但在这之前我们需要先搞明白在游戏中什么决定了前后左右各个方向。在游戏中,默认控制器方向为从摄像机到角色方向,但控制器还有一个旋转角度、远近和俯仰角度,通过将 GetControlRotaion() 函数俯仰和远近设置为零,就能等到旋转的 Yaw 值,将其转化为矢量,就是我们在使用 WASD 键时认为的前方。转化矢量的函数为 FRotationMatrix(const FRotator &Rot).GetUnitAxis(EAxis::Type Axis)。
然后我们就可以给控制器(APawn)绑定方向矢量,控制器就能接收键盘输入数据并在相应方向做出响应。
c
// 获取控制器并绑定方向向量
if (APawn* ControlledPawn = GetPawn<APawn>())
{
ControlledPawn->AddMovementInput(ForwardDirection, InputAxisVector.Y);
ControlledPawn->AddMovementInput(RightDirection, InputAxisVector.X);
}
绑定方向矢量的函数为 AddMovementInput(FVector WorldDirection, float ScaleValue, bool bForce /=false/),该函数有三个参数:第一个参数为 FVector,即我们前面拿到的 ForwardDirection、RightDirection 两个方向矢量,第二个参数可以视为单位,即每次按键触发移动的大小,通过入参 FInputActionValue 来获取,即 InputAxisVector 的 X 和 Y 值,最后一个参数为布尔类型,默认为 false,先不用管。
总结一下,就是我们告诉了控制器 APawn 在哪个方向移动多少距离。
总结
以上,我们在 AuraPlayerController 中(因为我们要使用它来统一控制角色的移动)添加了 Input Action(接收输入) 和 Input Mapping Context(绑定按键)变量,定义了 Move 函数并通过增强输入本地玩家子系统的增强输入组件(UEnhancedInputComponent)的 BindAction() 函数来将它与 Input Action 绑定,通过控制器来控制角色的前后左右移动。
因为 AuraPlayerController 继承自 Actor,而每个 Actor 都包含有输入组件(Input Action 对应这个输入组件),但需要将其转化增强输入组件才能使用用增强输入本地玩家子系统的功能,即 BindAction() 函数。
最后
到这里不知道你是不是会有一个疑问,就是:之前添加的 Input Action 蓝图和 Input Mapping Context 是如何与 AuraPlayerControlller 中的 MoveAction 和 AuraContext 两个变量绑定的?引擎怎么就知道将蓝图中的数据和行为映射到这两个变量中呢?
答案就是我们还需要添加一个蓝图类,名为 BP_AuraPlayerController,而它的父类就是 AuraPlayerController 类。
打开 UE,Blueprints 目录下添加文件夹 "Player",打开并新建蓝图类,选择 AuraPlayerController 为其父类,命名为 "BP_AuraPlayerController"。
打开 BP_AuraPlayerController 蓝图,其属性界面就会看到 Aura Context 和 Move Action 两个属性(从父类中继承过来),将 Aura Context 设置为之前添加的 IMC_AuraContext,将 Move Action 设置为 IA_Move 即可。