Spawn walkers at begin play and add a black list for misbehaving walkers
This commit is contained in:
parent
54cd5fa775
commit
795ec2e12e
|
@ -14,9 +14,24 @@
|
|||
// -- Static local methods -----------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
static bool WalkerIsValid(ACharacter *Walker)
|
||||
{
|
||||
return ((Walker != nullptr) && !Walker->IsPendingKill());
|
||||
}
|
||||
|
||||
static AWalkerAIController *GetController(ACharacter *Walker)
|
||||
{
|
||||
return (Walker != nullptr ? Cast<AWalkerAIController>(Walker->GetController()) : nullptr);
|
||||
return (WalkerIsValid(Walker) ? Cast<AWalkerAIController>(Walker->GetController()) : nullptr);
|
||||
}
|
||||
|
||||
static float GetDistance(const FVector &Location0, const FVector &Location1)
|
||||
{
|
||||
return FMath::Abs((Location0 - Location1).Size());
|
||||
}
|
||||
|
||||
static float GetDistance(const AActor &Actor0, const AActor &Actor1)
|
||||
{
|
||||
return GetDistance(Actor0.GetActorLocation(), Actor1.GetActorLocation());
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
@ -39,6 +54,8 @@ void AWalkerSpawnerBase::BeginPlay()
|
|||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
NumberOfWalkers = FMath::Max(0, NumberOfWalkers);
|
||||
|
||||
// Allocate space for walkers.
|
||||
Walkers.Reserve(NumberOfWalkers);
|
||||
|
||||
|
@ -50,14 +67,28 @@ void AWalkerSpawnerBase::BeginPlay()
|
|||
}
|
||||
|
||||
// Find spawn points present in level.
|
||||
for (TActorIterator<AWalkerSpawnPoint> It(GetWorld()); It; ++It) {
|
||||
SpawnPoints.Add(*It);
|
||||
TArray<AWalkerSpawnPointBase *> BeginSpawnPoints;
|
||||
for (TActorIterator<AWalkerSpawnPointBase> It(GetWorld()); It; ++It) {
|
||||
BeginSpawnPoints.Add(*It);
|
||||
AWalkerSpawnPoint *SpawnPoint = Cast<AWalkerSpawnPoint>(*It);
|
||||
if (SpawnPoint != nullptr) {
|
||||
SpawnPoints.Add(SpawnPoint);
|
||||
}
|
||||
}
|
||||
UE_LOG(LogCarla, Log, TEXT("Found %d positions for spawning walkers"), SpawnPoints.Num());
|
||||
UE_LOG(LogCarla, Log, TEXT("Found %d positions for spawning walkers at begin play."), BeginSpawnPoints.Num());
|
||||
UE_LOG(LogCarla, Log, TEXT("Found %d positions for spawning walkers during game play."), SpawnPoints.Num());
|
||||
|
||||
if (SpawnPoints.Num() < 2) {
|
||||
bSpawnWalkers = false;
|
||||
UE_LOG(LogCarla, Error, TEXT("We don't have enough spawn points for walkers!"));
|
||||
} else if (BeginSpawnPoints.Num() < NumberOfWalkers) {
|
||||
UE_LOG(LogCarla, Warning, TEXT("Requested %d walkers, but we only have %d spawn points. Some will fail to spawn."), NumberOfWalkers, BeginSpawnPoints.Num());
|
||||
}
|
||||
|
||||
if (bSpawnWalkers) {
|
||||
for (auto i = 0; i < NumberOfWalkers; ++i) {
|
||||
TryToSpawnWalkerAt(*BeginSpawnPoints[i % BeginSpawnPoints.Num()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,21 +96,38 @@ void AWalkerSpawnerBase::Tick(float DeltaTime)
|
|||
{
|
||||
Super::Tick(DeltaTime);
|
||||
|
||||
if (bSpawnWalkers && (NumberOfWalkers > Walkers.Num())) {
|
||||
if (bSpawnWalkers && (NumberOfWalkers > GetCurrentNumberOfWalkers())) {
|
||||
// Try to spawn one walker.
|
||||
TryToSpawnRandomWalker();
|
||||
TryToSpawnWalkerAt(GetRandomSpawnPoint());
|
||||
}
|
||||
|
||||
if (WalkersBlackList.Num() > 0) {
|
||||
// If still stuck in the black list, just kill it.
|
||||
const int32 Index = (++CurrentIndexToCheck % WalkersBlackList.Num());
|
||||
auto Walker = WalkersBlackList[Index];
|
||||
auto Controller = GetController(Walker);
|
||||
if ((Controller == nullptr) ||
|
||||
(Controller->GetMoveStatus() != EPathFollowingStatus::Moving)) {
|
||||
WalkersBlackList.RemoveAtSwap(Index);
|
||||
if (Walker != nullptr) {
|
||||
Walker->Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Walkers.Num() > 0) {
|
||||
// Check one walker and kill it if necessary.
|
||||
// Check one walker, if fails black-list it or kill it.
|
||||
const int32 Index = (++CurrentIndexToCheck % Walkers.Num());
|
||||
auto Walker = Walkers[Index];
|
||||
auto Controller = GetController(Walker);
|
||||
if ((Controller == nullptr) || (Controller->GetMoveStatus() != EPathFollowingStatus::Moving)) {
|
||||
if (Controller == nullptr) {
|
||||
Walkers.RemoveAtSwap(Index);
|
||||
if (Walker != nullptr) {
|
||||
Walker->Destroy();
|
||||
}
|
||||
} else if (Controller->GetMoveStatus() != EPathFollowingStatus::Moving) {
|
||||
WalkersBlackList.Add(Walker);
|
||||
Walkers.RemoveAtSwap(Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,45 +146,64 @@ void AWalkerSpawnerBase::SetNumberOfWalkers(const int32 Count)
|
|||
}
|
||||
}
|
||||
|
||||
void AWalkerSpawnerBase::TryToSpawnRandomWalker()
|
||||
const AWalkerSpawnPointBase &AWalkerSpawnerBase::GetRandomSpawnPoint() const
|
||||
{
|
||||
auto SpawnPoint = GetRandomSpawnPoint();
|
||||
auto DestinationPoint = GetRandomSpawnPoint();
|
||||
if ((SpawnPoint != nullptr) && (DestinationPoint != nullptr)) {
|
||||
const auto StraightDistance =
|
||||
DestinationPoint->GetActorLocation() -
|
||||
SpawnPoint->GetActorLocation();
|
||||
if (StraightDistance.Size() >= MinimumWalkDistance) {
|
||||
SpawnWalkerAtSpawnPoint(*SpawnPoint, DestinationPoint->GetActorLocation());
|
||||
}
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Unable to find spawn point"));
|
||||
}
|
||||
check(SpawnPoints.Num() > 0);
|
||||
return *SpawnPoints[RandomStream.RandRange(0, SpawnPoints.Num() - 1)];
|
||||
}
|
||||
|
||||
void AWalkerSpawnerBase::SpawnWalkerAtSpawnPoint(
|
||||
const AWalkerSpawnPoint &SpawnPoint,
|
||||
const FVector &Destination)
|
||||
bool AWalkerSpawnerBase::TryGetValidDestination(const FVector &Origin, FVector &Destination) const
|
||||
{
|
||||
const auto &DestinationPoint = GetRandomSpawnPoint();
|
||||
Destination = DestinationPoint.GetActorLocation();
|
||||
return (GetDistance(Origin, Destination) >= MinimumWalkDistance);
|
||||
}
|
||||
|
||||
bool AWalkerSpawnerBase::TryToSpawnWalkerAt(const AWalkerSpawnPointBase &SpawnPoint)
|
||||
{
|
||||
// Try find destination.
|
||||
FVector Destination;
|
||||
if (!TryGetValidDestination(SpawnPoint.GetActorLocation(), Destination)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Spawn walker.
|
||||
ACharacter *Walker;
|
||||
SpawnWalker(SpawnPoint.GetActorTransform(), Walker);
|
||||
if ((Walker != nullptr) && !Walker->IsPendingKill()) {
|
||||
Walker->AIControllerClass = AWalkerAIController::StaticClass();
|
||||
Walker->SpawnDefaultController();
|
||||
auto Controller = GetController(Walker);
|
||||
if (Controller != nullptr) { // Sometimes fails...
|
||||
Controller->MoveToLocation(Destination);
|
||||
Walkers.Add(Walker);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Something went wrong creating the controller for the new walker"));
|
||||
Walker->Destroy();
|
||||
}
|
||||
if (!WalkerIsValid(Walker)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assign controller.
|
||||
Walker->AIControllerClass = AWalkerAIController::StaticClass();
|
||||
Walker->SpawnDefaultController();
|
||||
auto Controller = GetController(Walker);
|
||||
if (Controller == nullptr) { // Sometimes fails...
|
||||
UE_LOG(LogCarla, Error, TEXT("Something went wrong creating the controller for the new walker"));
|
||||
Walker->Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add walker and set destination.
|
||||
Walkers.Add(Walker);
|
||||
Controller->MoveToLocation(Destination);
|
||||
return true;
|
||||
}
|
||||
|
||||
AWalkerSpawnPoint *AWalkerSpawnerBase::GetRandomSpawnPoint() const
|
||||
bool AWalkerSpawnerBase::TrySetDestination(ACharacter &Walker) const
|
||||
{
|
||||
return (SpawnPoints.Num() > 0 ?
|
||||
SpawnPoints[RandomStream.RandRange(0, SpawnPoints.Num() - 1)] :
|
||||
nullptr);
|
||||
// Try to retrieve controller.
|
||||
auto Controller = GetController(&Walker);
|
||||
if (Controller == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try find destination.
|
||||
FVector Destination;
|
||||
if (!TryGetValidDestination(Walker.GetActorLocation(), Destination)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Controller->MoveToLocation(Destination);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "WalkerSpawnerBase.generated.h"
|
||||
|
||||
class AWalkerSpawnPoint;
|
||||
class AWalkerSpawnPointBase;
|
||||
class UBoxComponent;
|
||||
|
||||
/// Base class for spawning walkers. Implement SpawnWalker in derived
|
||||
|
@ -64,13 +65,20 @@ public:
|
|||
|
||||
void SetNumberOfWalkers(int32 Count);
|
||||
|
||||
int32 GetCurrentNumberOfWalkers() const
|
||||
{
|
||||
return Walkers.Num() + WalkersBlackList.Num();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void TryToSpawnRandomWalker();
|
||||
const AWalkerSpawnPointBase &GetRandomSpawnPoint() const;
|
||||
|
||||
void SpawnWalkerAtSpawnPoint(const AWalkerSpawnPoint &SpawnPoint, const FVector &Destination);
|
||||
bool TryGetValidDestination(const FVector &Origin, FVector &Destination) const;
|
||||
|
||||
AWalkerSpawnPoint *GetRandomSpawnPoint() const;
|
||||
bool TryToSpawnWalkerAt(const AWalkerSpawnPointBase &SpawnPoint);
|
||||
|
||||
bool TrySetDestination(ACharacter &Walker) const;
|
||||
|
||||
/// @}
|
||||
|
||||
|
@ -105,5 +113,8 @@ private:
|
|||
UPROPERTY(Category = "Walker Spawner", VisibleAnywhere, AdvancedDisplay)
|
||||
TArray<ACharacter *> Walkers;
|
||||
|
||||
UPROPERTY(Category = "Walker Spawner", VisibleAnywhere, AdvancedDisplay)
|
||||
TArray<ACharacter *> WalkersBlackList;
|
||||
|
||||
uint32 CurrentIndexToCheck = 0u;
|
||||
};
|
||||
|
|
|
@ -172,7 +172,7 @@ APlayerStart *ACarlaGameModeBase::FindUnOccupiedStartPoints(
|
|||
if (!GetWorld()->EncroachingBlockingGeometry(PawnToFit, ActorLocation, ActorRotation)) {
|
||||
UnOccupiedStartPoints.Add(PlayerStart);
|
||||
}
|
||||
#ifdef WITH_EDITOR
|
||||
#if WITH_EDITOR
|
||||
else if (GetWorld()->FindTeleportSpot(PawnToFit, ActorLocation, ActorRotation)) {
|
||||
UE_LOG(
|
||||
LogCarla,
|
||||
|
|
Loading…
Reference in New Issue