PlayerController与Pawn
2024年1月8日 2024年1月12日
创建PlayerController的派生类并绑定键位
创建派生自APlayerController的C++类
- | |
---|---|
基类 | PlayerController |
属性 | Public |
名称 | GeometryPlayerController |
添加动作映射,按空格时切换当前Pawn
Project Settings > Engine > Input
- | |
---|---|
函数描述 | ChangePawn |
键位 | Space Bar |
实现切换Pawn逻辑
GeometryPlayerController
包含头文件
1#include "Engine/World.h" 2#include "Kismet/GameplayStatics.h" 3#include "GeometryPawn.h" 4#include "Components/InputComponent.h"
添加静态日志类型
1DEFINE_LOG_CATEGORY_STATIC(LogGeometryPlayerController, All, All)
添加数据成员: 保存Pawn的数组, 当前Pawn索引
private
1TArray<AActor*>Pawns; 2int32 CurrentPawnIndex = 0;
添加函数成员: 初始化Pawn数组
private
在BeginPlay中调用
获取场景中派生自AGeometryPawn的Pawn对象
1void AGeometryPlayerController::InitPawns() 2{ 3 UGameplayStatics::GetAllActorsOfClass(GetWorld(), AGeometryPawn::StaticClass(), Pawns); 4}
实现BeginPlay
1void AGeometryPlayerController::BeginPlay() { 2 Super::BeginPlay(); 3 InitPawns(); 4}
添加函数成员: 切换Pawn的回调函数
private
- Pawn个数为1时,切换无效
- 挨个轮转Pawn对象
1void AGeometryPlayerController::ChangePawn() 2{ 3 if (Pawns.Num() <= 1) 4 { 5 UE_LOG(LogGeometryPlayerController, Log, TEXT("Pawn Num %d"), Pawns.Num()); 6 return; 7 } 8 AGeometryPawn *CurrentPawn = Cast<AGeometryPawn>(Pawns[CurrentPawnIndex]); 9 CurrentPawnIndex = (CurrentPawnIndex + 1) % Pawns.Num(); 10 AGeometryPawn *NextPawn = Cast<AGeometryPawn>(Pawns[CurrentPawnIndex]); 11 12 if (!CurrentPawn || !NextPawn) return; 13 14 UE_LOG(LogGeometryPlayerController, Log, TEXT("%s switch pawn from %s to %s"), *GetName(), *CurrentPawn->GetName(), *NextPawn->GetName()); 15 16 Possess(NextPawn); 17}
添加函数成员: 绑定键位描述和回调函数
private
在SetupInputComponent中调用
为函数描述绑定回调函数
1void AGeometryPlayerController::BindChangePawn() 2{ 3 if (InputComponent) 4 { 5 InputComponent->BindAction("ChangePawn", IE_Pressed, this, &AGeometryPlayerController::ChangePawn); 6 } 7}
实现SetupInputComponent
1void AGeometryPlayerController::SetupInputComponent() 2{ 3 Super::SetupInputComponent(); 4 BindChangePawn(); 5}
设置关卡基础类型: PlayerController
包含头文件
1#include "GeometryPlayerController.h"
添加函数成员: 设置PlayerController的基础类型
private
在构造函数中调用
1void AGeometryGameModeBase::InitPlayerController() 2{ 3 PlayerControllerClass = AGeometryPlayerController::StaticClass(); 4}
比较Pawn和PlayerController键位绑定的位置
Pawn
在成员函数SetupPlayerInputComponent中完成,其参数为UInputComponent指针
PlayerController
继承自AController的成员函数SetupInputComponent
继承自AActor的数据成员InputComponent,其类型为UInputComponent指针
说明
- APawn和APlayerController都会处理输入
- 二者均继承自AActor:
APlayerController的输入处理来自AActor,而APawn对输入处理进行了封装
切换Pawn日志
在虚幻编辑器中查看GameMode基础类型
在虚幻编辑器中添加BP_GeometryPawn_Sphere实例,用以切换
-
初始状态
- PlayerController接管GeometryPawn
- AIController接管BP_GeometryPawn_Cube
- PlayerController接管GeometryPawn
-
第一次切换 PlayerController预备接管BP_GeometryPawn_Cube
- PlayerController释放GeometryPawn
- AIController释放BP_GeometryPawn_Cube
- PlayerController接管BP_GeometryPawn_Cube
- GeometryPawn处于等待接管状态
- PlayerController释放GeometryPawn
-
第二次切换 PlayerController预备接管GeometryPawn
- PlayerController释放BP_GeometryPawn_Cube
- PlayerController接管GeometryPawn
- BP_GeometryPawn_Cube处于等待接管状态
- PlayerController释放BP_GeometryPawn_Cube
-
第三次切换 PlayerController预备接管BP_GeometryPawn_Cube
- PlayerController释放GeometryPawn
- PlayerController接管BP_GeometryPawn_Cube
- GeometryPawn处于等待接管状态
- PlayerController释放GeometryPawn
-
结束游戏
PlayerController释放BP_GeometryPawn_Cube
对BP_GeometryPawn_Sphere实例禁用AI自动控制
-
默认
Placed in World
-
禁用
Disabled
-
日志
按住方向键切换Pawn,切换后,前Pawn仍在移动
情况说明:
- 基类UnPossessd函数中,会调用DestroyPlayerInputComponent函数,删除输入组件
- 即在删除输入组件之前,不会更新速度方向
解决思路:
- 在Tick函数的最后,复位速度矢量
- 只有当Pawn对象被使用时,调用VelocityInForce; 切换后,前Pawn不会移动,但切换回前Pawn,会保持移动
解决切换Pawn后, 前Pawn继续移动问题
GeometryPawn
添加函数成员: 在Tick函数的最后,复位速度矢量
private
在Tick函数的最后调用
1void AGeometryPawn::ClearVelocityVector() 2{ 3 VelocityVector = FVector::ZeroVector; 4}
在调用VelocityInForce之前,判断Pawn是否被接管
1// Called every frame 2void AGeometryPawn::Tick(float DeltaTime) 3{ 4 Super::Tick(DeltaTime); 5 6 if (IsPawnControlled()) 7 VelocityInForce(DeltaTime); 8 9 ClearVelocityVector(); 10}