输入映射上下文与输入操作
首先创建输入映射上下文与输入操作。输入映射上下文把按键转换为对应的数据传给输入操作,输入操作可绑定触发事件。
移动由四个方向键驱动前后左右所以值类型应该为Axis2D,跳跃仅捕获是否按下按键,值类型应为数字(布尔),旋转视角是鼠标在2D平面内旋转,旋转的输入操作值类型为Axis2D。其他设置不需要更改。
在输入映射上下文映射里添加输入操作,给移动的按键添加WASD。如果认为W为主方向,那么W可以报错默认。Axis2D数据类型下,所有按键在没有设置修改器的状态下默认都是添加X轴正方向的数值,我们需要为其他按键添加修改器更改他们控制的数值方向。S为W相反方向,所以S添加修改器否定,这样它就会增加X轴负方向的数值。A D方向与W S方向垂直,这两个都需要用到修改器拌合输入轴值,排序默认为YXZ,它的作用是交换X和Y轴,使得A D控制Y方向。A与D方向相反,所以其中一个需要再添加一个否定修改器。这里做的演示是给A添加了否定修改器。跳跃的按键直接添加一个空格就行。旋转的按键可以简单添加一个鼠标XY2D轴。
绑定函数
输入的逻辑一般写在playercontroller类里,当然也能写在角色类里。这里显示为playercontroller类。
创建一个继承自playercontroller类的c++类,再创建一个蓝图类继承自创建的c++类,在gamemode里把玩家控制器设置为创建的那个蓝图类。
在c++类里添加成员变量,使用UPROPERTY进行标记,使得它可以在继承它的蓝图类里设置该变量的默认值。UInputMappingContext是输入映射上下文,UInputAction是输入操作。虚幻引擎中对父类为UObjcet类使用裸指针是安全的,无需手动销毁或置空,并且也禁止直接delete。
//为了不在头文件中引入多余的头文件,可以在头文件的全局作用域内前向声明class UInputMappingContext、class UInputAction、struct FInputActionValue
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Input")
UInputMappingContext* playerInputMappingContext;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Input")
UInputAction* MoveAction; //移动
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Input")
UInputAction* JumpAction; //跳跃
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Input")
UInputAction* LookAction; //旋转
然后在继承自它的蓝图类里把创建的输入操作资产赋给这些变量。
重写父类函数,并且创建控制移动、跳跃、视角的函数,输入操作会传递一个FInputActionValue的参数,在移动与视角控制中我们需要此参数来确定转向方向。
virtual void BeginPlay() override;
virtual void SetupInputComponent() override;
class AmainCharacterBase* playerCharacter;
void move(const FInputActionValue& value);
void jump();
void look(const FInputActionValue& value);
如果在头文件中进行过前向声明,可以在cpp文件中需要导入头文件,在cpp中定义函数。
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
#include "InputActionValue.h"
void AmainPlayerController::BeginPlay()
{
Super::BeginPlay();
playerCharacter = Cast<AmainCharacterBase>(GetCharacter());//获取玩家对象引用
if (UEnhancedInputLocalPlayerSubsystem * Subsystem{ ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()) })
//在playercontroller里可以通过GetLocalPlayer()获取本地玩家,在其他类中也可以通过GetWorld()->GetFirstLocalPlayerFromController()获取第一个本地玩家
{
if (playerInputMappingContext)
Subsystem->AddMappingContext(playerInputMappingContext, 0);//0是一个整数参数代表权重。
}
}
//需要通过本地玩家获取增强输入本地玩家子系统,将输入映射上下文添加到子系统内。这是使用增强输入系统的必要操作。
void AmainPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
if (UEnhancedInputComponent* EnhancedInputComponent{ CastChecked<UEnhancedInputComponent>(InputComponent) })
{
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AmainPlayerController::move);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &AmainPlayerController::jump);
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AmainPlayerController::look);
}
//给输入操作绑定函数,ETriggerEvent::Triggered是按钮是按下的状态就会一直触发函数。ETriggerEvent::Started是按下按钮的时候触发一次函数。
}
void AmainPlayerController::move(const FInputActionValue& value)
{
FVector2D MovementVector{ value.Get<FVector2D>() };
if (playerCharacter)
{
//获取角色朝向
const FRotator Rotation{ this->GetControlRotation() };
const FRotator YawRotation{ 0, Rotation.Yaw, 0 };
// 计算移动方向
const FVector ForwardDirection{ FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y) };
const FVector RightDirection{ FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X) };
// 应用移动,如果你发现方向错误,可在MovementVector前面添加-或交换x、y来进行调整。
playerCharacter->AddMovementInput(ForwardDirection, MovementVector.Y);
playerCharacter->AddMovementInput(RightDirection, MovementVector.X);
}
}
void AmainPlayerController::jump()
{
if (playerCharacter)
{
playerCharacter->Jump();
}
}
void AmainPlayerController::look(const FInputActionValue& value)
{
FVector2D LookVector{ value.Get<FVector2D>() };
if (playerCharacter)
{
//添加控制器旋转。注意,如果你自己手动创建的玩家角色,可能发现上下旋转无效果,此时需要在角色类的摄像机组件打开使用Pawn控制旋转。
playerCharacter->AddControllerYawInput(LookVector.X);
playerCharacter->AddControllerPitchInput(LookVector.Y);
}
}