24. 为玩家绑定键盘事件

本教程将为角色添加一个 Action 键盘响应。首先,我们需要添加一个名为 Action 的输入选项,并将其绑定到键盘输入或控制器按钮上。在本例中,我们将把 Action 输入绑定到键盘的 F 键。转到 编辑>项目设置(Edit > Project Settings) 。然后选择 Input 选项。单击 操作映射(Action Mappings) 旁边的加号。输入动作的名为 Action,并从下拉菜单中选择 F

右键“新建C++类”,选择父类为角色(Character)。 在 xxxCharacter.h 文件中添加 OnFire 方法和 OnAction 方法。

protected:

    /** Fires a projectile. */
    void OnFire();

    // on action 
    void OnAction();

接下来,在 xxxCharacter.cpp 文件中,我们将找到 AxxxCharacter::SetupPlayerInputComponent 函数,并将 Action 映射与 OnAction 函数连接起来。我们之后马上会创建 OnAction 函数。我通过 PlayerInputComponent 中 的 BindAction 函数将控制器连接到 OnAction 函数。在这个例子中,每次按下键盘 F 时都会调用 OnAction 函数

PlayerInputComponent->BindAction("Action", IE_Pressed, this, &AUnrealCPPCharacter::OnAction);

最后,我们在xxxCharacter.cpp中添加 OnAction 函数。这将是一个非常简单的函数,用于将消息记录到屏幕上。

void AUnrealCPPCharacter::OnAction() 
{
    if (GEngine) 
    {
        GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("I'm Pressing Action"));
    }
}

游戏运行后,按下 F 键的效果图如下

指定的任意的 Pawn 绑定键盘相应事件

除了给玩家接收键盘响应,也可以给我们指定的任意的 Pawn 绑定键盘相应事件

首先,我们可以新建一个 MyPawn 类,注意其继承自 Pawn 类

MyPawn.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"

UCLASS()
class UNREALCPP_API AMyPawn : public APawn
{
    GENERATED_BODY()

public:
    // Sets default values for this pawn's properties
    AMyPawn();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public:
    // Called every frame
    virtual void Tick(float DeltaSeconds) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;

    UPROPERTY(EditAnywhere)
    USceneComponent* OurVisibleComponent;

    // Input functions
    void Move_XAxis(float AxisValue);
    void Move_YAxis(float AxisValue);
    void StartGrowing();
    void StopGrowing();

    // Input variables
    FVector CurrentVelocity;
    bool bGrowing;
};

接着在编辑器中,我们创建一个名为 Grow 的 Action 映射,并将其绑定到 G 键, 用于缩放。然后创建两个 Axis 映射用于平移,并将它们命名为 MoveX 和 MoveY 。将轴的比例分别设置为 1 和 -1 。

1. MoveX

I: Scale 1.0
K: Scale -1.0

2. MoveY
J: Scale -1.0
L: Scale 1.0

3. Grow
G

完整的 cpp 代码如下

#include "MyPawn.h"
#include "Camera/CameraComponent.h"
#include "Components/InputComponent.h"
#include "Components/StaticMeshComponent.h"

// Sets default values
AMyPawn::AMyPawn()
{
    // Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    // Set this pawn to be controlled by the lowest-numbered player
    AutoPossessPlayer = EAutoReceiveInput::Player0;

    // Create a dummy root component we can attach things to.
    RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
    // Create a camera and a visible object
    UCameraComponent* OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("OurCamera"));
    OurVisibleComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("OurVisibleComponent"));
    // Attach our camera and visible object to our root component. Offset and rotate the camera.
    OurCamera->SetupAttachment(RootComponent);
    OurCamera->SetRelativeLocation(FVector(-250.0f, 0.0f, 250.0f));
    OurCamera->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));
    OurVisibleComponent->SetupAttachment(RootComponent);

}

// Called every frame
void AMyPawn::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);


    // Handle growing and shrinking based on our "Grow" action
    {
        float CurrentScale = OurVisibleComponent->GetComponentScale().X;
        if (bGrowing)
        {
            // Grow to double size over the course of one second
            CurrentScale += DeltaTime;
        }
        else
        {
            // Shrink half as fast as we grow
            CurrentScale -= (DeltaTime * 0.5f);
        }
        // Make sure we never drop below our starting size, or increase past double size.
        CurrentScale = FMath::Clamp(CurrentScale, 1.0f, 2.0f);
        OurVisibleComponent->SetWorldScale3D(FVector(CurrentScale));
    }

    // Handle movement based on our "MoveX" and "MoveY" axes
    {
        if (!CurrentVelocity.IsZero())
        {
            FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
            SetActorLocation(NewLocation);
        }
    }

}

// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(InputComponent);

    // Respond when our "Grow" key is pressed or released.
    InputComponent->BindAction("Grow", IE_Pressed, this, &AMyPawn::StartGrowing);
    InputComponent->BindAction("Grow", IE_Released, this, &AMyPawn::StopGrowing);

    // Respond every frame to the values of our two movement axes, "MoveX" and "MoveY".
    InputComponent->BindAxis("MoveX", this, &AMyPawn::Move_XAxis);
    InputComponent->BindAxis("MoveY", this, &AMyPawn::Move_YAxis);

}

void AMyPawn::Move_XAxis(float AxisValue)
{
    // Move at 100 units per second forward or backward
    CurrentVelocity.X = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}

void AMyPawn::Move_YAxis(float AxisValue)
{
    // Move at 100 units per second right or left
    CurrentVelocity.Y = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}

void AMyPawn::StartGrowing()
{
    bGrowing = true;
}

void AMyPawn::StopGrowing()
{
    bGrowing = false;
}

效果图为

参考