赞
踩
本文是对虚幻5新特性插件Enhanced Input的使用学习和代码框架解读,将会从应用和底层两方面对该系统进行分析。
Enhanced Input是对虚幻原生Input系统的拓展,其对输入的处理思路和原Input系统在流程上的思路是一致的。所不同的在于,对一些核心概念进行了提取和抽象,如Action和Action Context。不仅如此,在新框架的加持下,更多的功能特性可以得到发挥,如点触和持续按下等触发操作等。
Enhanced Input是以内置插件的形式提供,在Plugins面板,勾选并重启引擎即可激活:
在ContentBrowser里右键,可以看到已经出现了Input相关的新的条目,主要是InputAction资产和InputMapContext资产,说明插件激活成功。
然后需要到项目设置里的Input分栏里,修改默认类的设置:
随后,在代码层面需要在项目的Build.cs文件中添加相应的依赖模块:
public class InsideEnhancedInput : ModuleRules
{
public InsideEnhancedInput(ReadOnlyTargetRules Target) : base(Target)
{
...
PrivateDependencyModuleNames.AddRange(new string[] {"EnhancedInput"});
}
}
这样,不论在Editor里还是项目代码里,我们都可以自由的使用Enhanced Input相关内容了。
第三人称模板的输入的初识设置主要还是通过在Input->Bindings界面将输入的字符串和按键进行绑定,再在代码/蓝图中为动作(使用字符串)绑定好相应的回调事件。
相应的输入绑定代码:
// // Input void AInsideEnhancedInputCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) { // Set up gameplay key bindings check(PlayerInputComponent); PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump); PlayerInputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping); PlayerInputComponent->BindAxis("Move Forward / Backward", this, &AInsideEnhancedInputCharacter::MoveForward); PlayerInputComponent->BindAxis("Move Right / Left", this, &AInsideEnhancedInputCharacter::MoveRight); // We have 2 versions of the rotation bindings to handle different kinds of devices differently // "turn" handles devices that provide an absolute delta, such as a mouse. // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick PlayerInputComponent->BindAxis("Turn Right / Left Mouse", this, &APawn::AddControllerYawInput); PlayerInputComponent->BindAxis("Turn Right / Left Gamepad", this, &AInsideEnhancedInputCharacter::TurnAtRate); PlayerInputComponent->BindAxis("Look Up / Down Mouse", this, &APawn::AddControllerPitchInput); PlayerInputComponent->BindAxis("Look Up / Down Gamepad", this, &AInsideEnhancedInputCharacter::LookUpAtRate); // handle touch devices PlayerInputComponent->BindTouch(IE_Pressed, this, &AInsideEnhancedInputCharacter::TouchStarted); PlayerInputComponent->BindTouch(IE_Released, this, &AInsideEnhancedInputCharacter::TouchStopped); }
首先创建输入相关的资产,包括5个InputAction:
IA_MoveForward动作资产配置举例:
再创建1个InputMappingContext,将前面新建的诸多动作资产添加入内(记得对轴对应的按键中的一个作取反Negate
操作,否则两个按键将对应同一行为,如MoveForward中对S键取反),并添加相应的按键绑定:
所有资产在ContentBrowser视图下的显示:
代码层面,进入Character类(自定义的继承自Character类),改写其中部分代码:
UCLASS(config=Game) class AInsideEnhancedInputCharacter : public ACharacter { ... UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="EnhancedInput") UInputMappingContext* InputMappingContext; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="EnhancedInput|Action") UInputAction* IA_MoveForward; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="EnhancedInput|Action") UInputAction* IA_MoveRight; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="EnhancedInput|Action") UInputAction* IA_Turn; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="EnhancedInput|Action") UInputAction* IA_LookUp; UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category="EnhancedInput|Action") UInputAction* IA_Jump; protected: /** Called for forwards/backward input */ void MoveForward(const FInputActionValue& Value); /** Called for side to side input */ void MoveRight(const FInputActionValue& Value); /** * Called via input to turn at a given rate. * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate */ void TurnAtRate(const FInputActionValue& Value); /** * Called via input to turn look up/down at a given rate. * @param Rate This is a normalized rate, i.e. 1.0 means 100% of desired turn rate */ void LookUpAtRate(const FInputActionValue& Value); ...
... void AInsideEnhancedInputCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { // 保留原Input系统的输入响应 Super::SetupPlayerInputComponent(PlayerInputComponent); if(APlayerController* PC = CastChecked<APlayerController>(GetController())) { if(UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer())) { Subsystem->AddMappingContext(InputMappingContext, 100); } } if(UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) { if(IA_MoveForward) { EnhancedInputComponent->BindAction(IA_MoveForward, ETriggerEvent::Triggered, this, &AInsideEnhancedInputCharacter::MoveForward); } if(IA_MoveRight) { EnhancedInputComponent->BindAction(IA_MoveRight, ETriggerEvent::Triggered, this, &AInsideEnhancedInputCharacter::MoveRight); } if(IA_Turn) { EnhancedInputComponent->BindAction(IA_Turn, ETriggerEvent::Triggered, this, &AInsideEnhancedInputCharacter::TurnAtRate); } if(IA_LookUp) { EnhancedInputComponent->BindAction(IA_LookUp, ETriggerEvent::Triggered, this, &AInsideEnhancedInputCharacter::LookUpAtRate); } if(IA_Jump) { EnhancedInputComponent->BindAction(IA_Jump, ETriggerEvent::Started, this, &AInsideEnhancedInputCharacter::Jump); EnhancedInputComponent->BindAction(IA_Jump, ETriggerEvent::Completed, this, &AInsideEnhancedInputCharacter::StopJumping); } } } ... void AInsideEnhancedInputCharacter::TurnAtRate(const FInputActionValue& Value) { // calculate delta for this frame from the rate information AddControllerYawInput(Value.GetMagnitude() * TurnRateGamepad * GetWorld()->GetDeltaSeconds()); } void AInsideEnhancedInputCharacter::LookUpAtRate(const FInputActionValue& Value) { // calculate delta for this frame from the rate information AddControllerPitchInput(Value.GetMagnitude() * TurnRateGamepad * GetWorld()->GetDeltaSeconds()); } void AInsideEnhancedInputCharacter::MoveForward(const FInputActionValue& Value) { if ((Controller != nullptr) && (Value.IsNonZero())) { // find out which way is forward const FRotator Rotation = Controller->GetControlRotation(); const FRotator YawRotation(0, Rotation.Yaw, 0); // get forward vector const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X); AddMovementInput(Direction, Value.GetMagnitude()); } } void AInsideEnhancedInputCharacter::MoveRight(const FInputActionValue& Value) { if ( (Controller != nullptr) && (Value.IsNonZero()) ) { // find out which way is right const FRotator Rotation = Controller->GetControlRotation(); const FRotator YawRotation(0, Rotation.Yaw, 0); // get right vector const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y); // add movement in that direction AddMovementInput(Direction, Value.GetMagnitude()); } }
这样,编译过后,在相应的Character蓝图界面,可以进行绑定:
最终效果视频:
到这里,我们基本就用EnhancedInput完成了对第三人称模板的改造。
当然还没完,如果只是能够完成之前就已有的工作,那并不能说明这套新玩意的必要性。后面我们来逐渐引入一些不同的特性。
简单总结,在EnhancedInput输入系统的扩展下,我们多了一些可以操作配置的资产,是我们能够实现输入时做一些特别的事情,比如IMC可以让我们配置动作和按键的映射,可以让我们指定哪些输入是生效的;比如IA可以让我们定义一个个的动作;比如Modifier和Trigger可以配置按键生效的条件和生效的效果等等。
普通游戏开发并不需要了解核心代码的部分,掌握其使用已经颇为难得,阅读代码可以进一步加深输入配置、输入响应的流程的理解,但是究其目的本源的话,还是希望以此精进自己对引擎的理解,提升自己的综合能力。
虚幻 5.0 Documentation - Lyra Input Settings
知乎作者 Yimi81 的文章《UE5 – EnhancedInput(增强输入系统)》
虚幻中文直播第39期
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。