回合中重建游戏角色
2023年11月15日 2024年1月11日
Reset All Players
说明
回合每次开始时, 重新创建所有游戏角色, 让他们呆在初始位置
回合结束时, 游戏角色会被销毁
通过Controller完成: Controller自创建后一直存在于场景中
添加接口: 通过Controller重建游戏角色
private
ShootThemUp: STUGameModeBase.h
1void ResetOnePlayer(AController *Controller);
如果游戏角色未死亡: 销毁控制器当前控制的游戏角色
- | |
---|---|
APawn::Reset | 调用Destroy销毁Pawn: 当前Pawn上级Controller一定存在, 需满足控制器拥有PlayerState条件 |
1if (Controller && Controller->GetPawn()) 2{ 3 Controller->GetPawn()->Reset(); 4}
通过RestartPlayer创建游戏角色
- | |
---|---|
AGameModeBase::RestartPlayer > AGameModeBase::RestartPlayerAtPlayerStart | 只有当控制器名下没有Pawn时才会创建Pawn |
完整实现
ShootThemUp: STUGameModeBase.cpp
1void ASTUGameModeBase::ResetOnePlayer(AController *Controller) 2{ 3 if (Controller && Controller->GetPawn()) 4 { 5 Controller->GetPawn()->Reset(); 6 } 7 8 RestartPlayer(Controller); 9}
添加接口: 遍历所有Controller, 重建其名下游戏角色
private
ShootThemUp: STUGameModeBase.h
1void ResetPlayers();
- | |
---|---|
UWorld::GetControllerIterator | 获取控制器列表的迭代器 |
通过迭代器的Get方法得到指向Controller的指针
ShootThemUp: STUGameModeBase.cpp
1void ASTUGameModeBase::ResetPlayers() 2{ 3 if (!GetWorld()) return; 4 for (auto It = GetWorld()->GetControllerIterator(); It; ++It) 5 { 6 ResetOnePlayer(It->Get()); 7 } 8}
回合结束时, 调用ResetPlayers重新创建游戏角色
ShootThemUp: STUGameModeBase.cpp
1// GameTimerUpdate 2 3if (CurrentRound + 1 <= GameData.RoundsNum) 4 { 5 ++CurrentRound; 6 ResetPlayers(); 7 StartRound(); 8 }
查看
BP_STUGameModeBase
回合结束后, 创建了超多NPC
NPC的AutoPossessAI参数
BP_STUAICharacter
当前AutoPossessAI的值为Placed in World or Spawned: 当在关卡中添加游戏角色, 或者在代码中动态创建, 会为游戏角色创建上级控制器
这也是为什么在动态创建NPC那节会出现6个控制器的原因, 除了我们创建的3个, 当控制器创建NPC时, 虚幻引擎根据设置为这3个NPC又创建了控制器
当前有2个AIController
而当第一个回合结束, 下一回合开始, 使用迭代器遍历控制器时, 不停创建新NPC, 不停创建新控制器, 真是遍历不完
将 BP_STUAICharacter > AutoPossessAI
设为Disabled
再次查看
AIController个数正常
所有回合结束, 玩家操控的游戏角色重新生成三次, 而NPC仍是同一个
只有一个PlayerState
AIController的WantsPlayerState参数
之前在Reset函数中讲到, 如果控制器没有PlayerState, 不会对名下Pawn调用Destroy
因此, NPC没有被销毁, RestartPlayer中也没有重新创建Pawn
PlayerController会自动创建PlayerState, AIController需要指示创建: 通过将WantsPlayerState设为true
查看
有两个PlayerState
一局结束时, 所有游戏角色均重建三次, 标号从0开始
在代码中查看AutoPossessAI
- |
---|
Disabled |
PlacedInWorld |
Spawned |
PlacedInWorldOrSpawned |
- APawn构造函数中, AutoPossesAI的默认值为PlacedInWorld
- 在APawn::PostInitializeComponents中左右控制器的生成
当值为不为Disabled时, Pawn会调用SpawnDefaultController创建Controller
1void APawn::PostInitializeComponents() 2{ 3 QUICK_SCOPE_CYCLE_COUNTER(STAT_Pawn_PostInitComponents); 4 5 Super::PostInitializeComponents(); 6 7 if (IsValid(this)) 8 { 9 UWorld* World = GetWorld(); 10 11 // Automatically add Controller to AI Pawns if we are allowed to. 12 if (AutoPossessPlayer == EAutoReceiveInput::Disabled 13 && AutoPossessAI != EAutoPossessAI::Disabled && Controller == nullptr && GetNetMode() != NM_Client 14#if WITH_EDITOR 15 && (GIsEditor == false || World->IsGameWorld()) 16#endif // WITH_EDITOR 17 ) 18 { 19 const bool bPlacedInWorld = (World->bStartup); 20 if ((AutoPossessAI == EAutoPossessAI::PlacedInWorldOrSpawned) || 21 (AutoPossessAI == EAutoPossessAI::PlacedInWorld && bPlacedInWorld) || 22 (AutoPossessAI == EAutoPossessAI::Spawned && !bPlacedInWorld)) 23 { 24 SpawnDefaultController(); 25 } 26 } 27 28 // update movement component's nav agent values 29 UpdateNavAgent(); 30 } 31}
在代码中设置AutoPossessAI和WantsPlayerState的方法
-
AutoPossessAI
ShootThemUp: AI/STUAICharacter.cpp
1// 构造函数 2 3AutoPossessAI = EAutoPossessAI::Disabled;
-
WantsPlayerState
ShootThemUp: AI/STUAIController.cpp
1// 构造函数 2 3bWantsPlayerState = true;