玩家输入与Pawn
这个时组件和碰撞的提前知识预备,最好在之前了解组件相关东西,重要的概念对于轴映射和操作映射。
首先介绍两个概念
- Actor类——可以放到游戏场景中的游戏对象的基本类型。你如果想放置任何东西到游戏场景中,必须继承Actor类
- Pawn类——代表你或者代表电脑的人工智能的游戏对象,它是可以在屏幕上控制的游戏对象。Pawn类是从Actor类中继承的,它可以通过玩家的设备(键盘、鼠标等)控制或者被人工智能脚本控制。如果它是被玩家控制的,我们通常称之为controller(控制器);如果它是被人工智能脚本控制的,我们通常称之为AI(Artificial Intelligence,人工智能),如果你经常玩游戏,那些NPC(Non-player Characters,非玩家角色)就通常具有AI行为。
自己定义Pawn
- 打开UE4的C++项目,添加C++类,命名为MyPawn
- 在cpp中设置玩家控制
// 将该Pawn设为由最小编号玩家控制
AutoPossessPlayer = EAutoReceiveInput::Player0;
- 构建几个组件,在MyPawn.h底部添加
UPROPERTY(EditAnywhere)
USceneComponent* OurVisibleComponent;
《Inside UE4》-GamePlay架构系列博客
首先要知道一个对象要在3D世界中的表示,必然要携带一个Transform来表示其位置。但是在UE看来,Actor并不只是3D中的表示,一些不在世界中展示的“不可见对象”也可以是Actor,比如AInfo的派生类等,所以Actor也就没有自带Transform了。
而SceneComponent则封装了Transform,当作RootComponent,所以需要位置表示的Actor就可以向Actor中添加ScenetComponent作为其RootComponent.比如,pawn就自动创建了SceneComponent.
还有一点需要注意的是,实际中大部分的Actor是有Transform的,所以我们会经常设置获取它的坐标,常理来说,我们的需要先获取下SceneComponent,然后才能操作其Transform等相应接口,但是这样太过繁琐,因此UE为我们直接提供了基于Actor的接口,如Get/Set ActorLocation,但其实这些接口内部也是转发到RootComponent(SceneComponent)的。
- 将下面代码添加到cpp中构造函数AMyPawn::AMyPawn
这里需要在开头添加
#include "Camera/CameraComponent.h"
// 创建可附加内容的虚拟根组件。
RootComponent = CreateDefaultSubobject(TEXT("RootComponent"));
// 创建相机和可见对象
UCameraComponent* OurCamera = CreateDefaultSubobject(TEXT("OurCamera"));
OurVisibleComponent = CreateDefaultSubobject(TEXT("OurVisibleComponent"));
// 将相机和可见对象附加到根组件。偏移并旋转相机。
OurCamera->SetupAttachment(RootComponent);
OurCamera->SetRelativeLocation(FVector(-250.0f, 0.0f, 250.0f));
OurCamera->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f));
OurVisibleComponent->SetupAttachment(RootComponent);
- 现在便拥有响应游戏输入的自定义Pawn,需定义此输入的内容。为此,将在 虚幻编辑器 中配置项目的 输入设置。
配置游戏输入
输入的映射有两种——操作和轴
操作映射
适用于"是/否"输入,例如鼠标或手柄上的按钮。被按下、松开、双击或短时长按时,其将进行报告。跳跃、射击或与物体互动等离散操作是这类映射的理想对象。
轴映射
是连续的,可将其视为"程度"输入,例如手柄上的摇杆,或者鼠标光标的位置。其会逐帧报告自身的值,即使未移动也进行报告。通常使用此方法处理如行走、四处查看和操纵车辆等有量级或方向的对象。
虽然可直接在代码中定义输入映射,但常用方法是在 虚幻引擎 编辑器中定义,本教程也将使用此方法。
- 在 虚幻引擎编辑器中,在 编辑 下拉菜单下,点击 项目设置(Project Settings) 选项。
- 在此界面左侧的 引擎(Engine) 部分中选择 输入 选项。之后,展开右侧显示的 绑定 类别,添加 操作映射(Action Mapping) 和两个轴映射(Axis Mappings)。
[图片上传失败...(image-76b742-1623143400720)] - 输入现已配置完成,接下来在关卡中设置MyPawn。MyPawn 类将在 内容浏览器 中显示,并可被拖入 关卡编辑器。[图片上传失败...(image-76a21f-1623143400720)]
- 设置MyPawn还需一个步骤。需向其指定 静态网格体,以便其可在游戏中显示。具体操作:选择刚创建的MyPawn,在 细节面板 中选择名为 OurVisibleComponent (Inherited) 的组件,并利用 静态网格体 类别中的下拉框向其指定资源。在本教程中,Shape_Cylinder 为现成资源。 [图片上传失败...(image-62bd6a-1623143400720)]
- 现在保存关卡,返回 Visual Studio 编写代码,使刚刚放置的MyPawn对定义的输入做出反应。
编写和绑定游戏操作
- 在 Visual Studio 中,打开MyPawn.h并将以下代码添加到MyPawn类定义的底部:
四个输入函数将被绑定到输入事件。其运行时,将对新输入变量中存储的值进行更新,MyPawn将使用此类值决定游戏期间应执行的操作。
//输入函数
void Move_XAxis(float AxisValue);
void Move_YAxis(float AxisValue);
void StartGrowing();
void StopGrowing();
//输入变量
FVector CurrentVelocity;
bool bGrowing;
- 切换到MyPawn.cpp,并对刚才声明的四个函数编码。
使用 FMath::Clamp 约束输入中得到的值,将其约束在-1到+1的范围内。虽然本例中不存在此问题,但若有会对轴产生相同影响的多个键,则玩家同时按下此类输入时会将累加这些值。例如,如W键和向上方向键均映射到MoveX,且缩放均为1.0,同时按下这两个键会得到2.0的AxisValue。如不进行限制,玩家将以两倍速度移动。
void AMyPawn::Move_XAxis(float AxisValue)
{
// 以100单位/秒的速度向前或向后移动
CurrentVelocity.X = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}
void AMyPawn::Move_YAxis(float AxisValue)
{
// 以100单位/秒的速度向右或向左移动
CurrentVelocity.Y = FMath::Clamp(AxisValue, -1.0f, 1.0f) * 100.0f;
}
void AMyPawn::StartGrowing()
{
bGrowing = true;
}
void AMyPawn::StopGrowing()
{
bGrowing = false;
}
可以看到,两个"Move"函数将轴值视作浮点,而"Grow"则不同。这是因为其映射到MoveX和MoveY,均为轴映射,因此拥有浮点参数。操作映射无此参数。
- 现在已定义输入函数,接下来需进行绑定,以便对相应输入做出反应。将以下代码添加到 AMyPawn::SetupPlayerInputComponent 中:
// 在按下或松开"Grow"键时做出响应。
InputComponent->BindAction("Grow", IE_Pressed, this, &AMyPawn::StartGrowing);
InputComponent->BindAction("Grow", IE_Released, this, &AMyPawn::StopGrowing);
// 对两个移动轴"MoveX"和"MoveY"的值逐帧反应。
InputComponent->BindAxis("MoveX", this, &AMyPawn::Move_XAxis);
InputComponent->BindAxis("MoveY", this, &AMyPawn::Move_YAxis);
- 变量现在将根据配置的输入进行更新。接下来只需编写代码使其完成部分操作。将以下代码添加到 AMyPawn::Tick:
// 根据"Grow"操作处理增长和缩减
{
float CurrentScale = OurVisibleComponent->GetComponentScale().X;
if (bGrowing)
{
// 一秒内增长到两倍大小
CurrentScale += DeltaTime;
}
else
{
// 以增长速度缩减一半
CurrentScale -= (DeltaTime * 0.5f);
}
// 确保不会降至初始大小以下,或者增至两倍大小以上。
CurrentScale = FMath::Clamp(CurrentScale, 1.0f, 2.0f);
OurVisibleComponent->SetWorldScale3D(FVector(CurrentScale));
}
// 根据"MoveX"和"MoveY"轴处理移动
{
if (!CurrentVelocity.IsZero())
{
FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
SetActorLocation(NewLocation);
}
}
- 编译代码后,可返回 虚幻编辑器 并按 运行。应可使用WASD键控制 Pawn,同时可通过长按 空格 键来使其增长,松开空格键时看到缩小。