Merge pull request #333 from carla-simulator/Optimizations

Optimizations
This commit is contained in:
Néstor Subirón 2018-04-13 12:27:41 +02:00 committed by GitHub
commit ca14d4c8ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 517 additions and 198 deletions

View File

@ -35,6 +35,11 @@ vsproject: MY_CMAKE_FLAGS+=-DCMAKE_BUILD_TYPE=Release
vsproject: MY_CMAKE_FLAGS+=-G "Visual Studio 14 2015 Win64"
vsproject: call_cmake
vsproject15: BUILD_FOLDER=$(BASE_BUILD_FOLDER)/visualstudio
vsproject15: MY_CMAKE_FLAGS+=-DCMAKE_BUILD_TYPE=Release
vsproject15: MY_CMAKE_FLAGS+=-G "Visual Studio 15 2017 Win64"
vsproject15: call_cmake
build_linux: MY_CMAKE_FLAGS+=-G "Ninja"
build_linux: call_cmake
@cd $(BUILD_FOLDER) && ninja && ninja install

View File

@ -8,7 +8,11 @@ rem FOR %%G IN (Binaries,Intermediate,Plugins\Carla\Binaries,Plugins\Carla\Inter
rem echo Making CarlaServer...
rem call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
rem Visual Studio 2017 Enterprise:
rem call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat"
rem START /wait cmd.exe /k "cd Plugins\Carla & make clean default & pause & exit"
rem echo Launch editor...
rem start CarlaUE4.uproject

View File

@ -97,4 +97,4 @@
"Enabled": false
}
]
}
}

View File

@ -77,3 +77,5 @@ InitialAverageFrameRate=0.016667
PhysXTreeRebuildRate=10
[/Script/AIModule.CrowdManager]
MaxAgents=1000

View File

@ -16,7 +16,7 @@
"Modules": [
{
"Name": "Carla",
"Type": "Developer",
"Type": "Runtime",
"LoadingPhase": "PreDefault",
"AdditionalDependencies": [
"Engine"

View File

@ -8,14 +8,16 @@
#include "Carla.h"
#include "AgentComponent.h"
#include "Engine/World.h"
#include "Game/CarlaGameModeBase.h"
#include "Game/DataRouter.h"
#include "Engine/Engine.h"
#include "Kismet/GameplayStatics.h"
static FDataRouter &GetDataRouter(UWorld *World)
{
check(World != nullptr);
auto *GameMode = Cast<ACarlaGameModeBase>(World->GetAuthGameMode());
ACarlaGameModeBase *GameMode = Cast<ACarlaGameModeBase>(World->GetAuthGameMode());
check(GameMode != nullptr);
return GameMode->GetDataRouter();
}
@ -40,7 +42,20 @@ void UAgentComponent::BeginPlay()
if (bRegisterAgentComponent)
{
GetDataRouter(GetWorld()).RegisterAgent(this);
/**
* This only returns true if the current game mode is not null
* because you can only access a game mode if you are the host
* @param oftheworld UWorld is needed to access the game mode
* @return true if there is a game mode and it is not null
*/
if(UGameplayStatics::GetGameMode(GetWorld())!=nullptr)
{
GetDataRouter(GetWorld()).RegisterAgent(this);
} else
{
UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
if(GameInstance) GameInstance->GetDataRouter().RegisterAgent(this);
}
bAgentComponentIsRegistered = true;
}
}
@ -49,9 +64,19 @@ void UAgentComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (bAgentComponentIsRegistered)
{
GetDataRouter(GetWorld()).DeregisterAgent(this);
if(UGameplayStatics::GetGameMode(GetWorld())!=nullptr)
{
GetDataRouter(GetWorld()).DeregisterAgent(this);
}
else
{
UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(UGameplayStatics::GetGameInstance(GetWorld()));
if(GameInstance)
GameInstance->GetDataRouter().DeregisterAgent(this);
}
bAgentComponentIsRegistered = false;
}
Super::EndPlay(EndPlayReason);
}

View File

@ -202,7 +202,7 @@ void ACarlaGameModeBase::BeginPlay()
void ACarlaGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
Super::EndPlay(EndPlayReason);
if (CarlaSettingsDelegate != nullptr)
if (CarlaSettingsDelegate != nullptr && EndPlayReason!=EEndPlayReason::EndPlayInEditor)
{
CarlaSettingsDelegate->Reset();
}

View File

@ -8,15 +8,17 @@
#include "SceneCaptureCamera.h"
#include "Sensor/SensorDataView.h"
#include "Game/CarlaGameInstance.h"
#include "Settings/CarlaSettings.h"
#include "Components/DrawFrustumComponent.h"
#include "Components/SceneCaptureComponent2D.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/CollisionProfile.h"
#include "Engine/TextureRenderTarget2D.h"
#include "HighResScreenshot.h"
#include "Materials/Material.h"
#include "Paths.h"
#include "Kismet/KismetSystemLibrary.h"
#include <memory>
#include "ConstructorHelpers.h"
static constexpr auto DEPTH_MAT_PATH =
@ -33,6 +35,8 @@ static constexpr auto SEMANTIC_SEGMENTATION_MAT_PATH =
static void RemoveShowFlags(FEngineShowFlags &ShowFlags);
uint32 ASceneCaptureCamera::NumSceneCapture = 0;
ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer),
SizeX(720u),
@ -42,7 +46,7 @@ ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitial
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickGroup = TG_PrePhysics;
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CamMesh0"));
MeshComp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CamMesh"));
MeshComp->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
@ -51,28 +55,30 @@ ASceneCaptureCamera::ASceneCaptureCamera(const FObjectInitializer& ObjectInitial
MeshComp->PostPhysicsComponentTick.bCanEverTick = false;
RootComponent = MeshComp;
DrawFrustum = CreateDefaultSubobject<UDrawFrustumComponent>(TEXT("DrawFrust0"));
DrawFrustum = CreateDefaultSubobject<UDrawFrustumComponent>(TEXT("DrawFrust"));
DrawFrustum->bIsEditorOnly = true;
DrawFrustum->SetupAttachment(MeshComp);
CaptureRenderTarget = CreateDefaultSubobject<UTextureRenderTarget2D>(TEXT("CaptureRenderTarget0"));
CaptureRenderTarget = CreateDefaultSubobject<UTextureRenderTarget2D>(FName(*FString::Printf(TEXT("CaptureRenderTarget%d"),NumSceneCapture)));
#if WITH_EDITORONLY_DATA
CaptureRenderTarget->CompressionNoAlpha = true;
CaptureRenderTarget->MipGenSettings = TextureMipGenSettings::TMGS_NoMipmaps;
CaptureRenderTarget->bUseLegacyGamma = false;
#endif
CaptureRenderTarget->CompressionSettings = TextureCompressionSettings::TC_Default;
CaptureRenderTarget->SRGB=0;
CaptureRenderTarget->SRGB = false;
CaptureRenderTarget->bAutoGenerateMips = false;
CaptureRenderTarget->AddressX = TextureAddress::TA_Clamp;
CaptureRenderTarget->AddressY = TextureAddress::TA_Clamp;
CaptureComponent2D = CreateDefaultSubobject<USceneCaptureComponent2D>(TEXT("SceneCaptureComponent2D"));
CaptureComponent2D->SetupAttachment(MeshComp);
CaptureComponent2D->SetupAttachment(MeshComp);
// Load post-processing materials.
static ConstructorHelpers::FObjectFinder<UMaterial> DEPTH(DEPTH_MAT_PATH);
PostProcessDepth = DEPTH.Object;
static ConstructorHelpers::FObjectFinder<UMaterial> SEMANTIC_SEGMENTATION(SEMANTIC_SEGMENTATION_MAT_PATH);
PostProcessSemanticSegmentation = SEMANTIC_SEGMENTATION.Object;
NumSceneCapture++;
}
void ASceneCaptureCamera::PostActorCreated()
@ -105,29 +111,69 @@ void ASceneCaptureCamera::BeginPlay()
// Setup render target.
const bool bInForceLinearGamma = bRemovePostProcessing;
CaptureRenderTarget->InitCustomFormat(SizeX, SizeY, PF_B8G8R8A8, bInForceLinearGamma);
if(!IsValid(CaptureComponent2D)||CaptureComponent2D->IsPendingKill())
{
CaptureComponent2D = NewObject<USceneCaptureComponent2D>(this,TEXT("SceneCaptureComponent2D"));
CaptureComponent2D->SetupAttachment(MeshComp);
}
CaptureComponent2D->Deactivate();
CaptureComponent2D->TextureTarget = CaptureRenderTarget;
// Setup camera post-processing.
if (PostProcessEffect != EPostProcessEffect::None) {
CaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR; //HD is much slower!
// Setup camera post-processing depending on the quality level:
const UCarlaGameInstance* GameInstance = Cast<UCarlaGameInstance>(GetWorld()->GetGameInstance());
check(GameInstance!=nullptr);
const UCarlaSettings& CarlaSettings = GameInstance->GetCarlaSettings();
switch(PostProcessEffect)
{
case EPostProcessEffect::None: break;
case EPostProcessEffect::SceneFinal:
{
//we set LDR for high quality because it will include post-fx
//and HDR for low quality to avoid high contrast
switch(CarlaSettings.GetQualitySettingsLevel())
{
case EQualitySettingsLevel::Low:
CaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_SceneColorHDRNoAlpha;
break;
default:
//LDR is faster than HDR (smaller bitmap array)
CaptureComponent2D->CaptureSource = ESceneCaptureSource::SCS_FinalColorLDR;
break;
}
break;
}
default:
CaptureComponent2D->CaptureSource = SCS_FinalColorLDR;
break;
}
if (bRemovePostProcessing) {
if (bRemovePostProcessing)
{
RemoveShowFlags(CaptureComponent2D->ShowFlags);
}
if (PostProcessEffect == EPostProcessEffect::Depth) {
if (PostProcessEffect == EPostProcessEffect::Depth)
{
CaptureComponent2D->PostProcessSettings.AddBlendable(PostProcessDepth, 1.0f);
} else if (PostProcessEffect == EPostProcessEffect::SemanticSegmentation) {
} else if (PostProcessEffect == EPostProcessEffect::SemanticSegmentation)
{
CaptureComponent2D->PostProcessSettings.AddBlendable(PostProcessSemanticSegmentation, 1.0f);
}
CaptureComponent2D->UpdateContent();
CaptureComponent2D->Activate();
//Make sure that there is enough time in the render queue
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), FString("g.TimeoutForBlockOnRenderFence 300000"));
Super::BeginPlay();
}
void ASceneCaptureCamera::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if(NumSceneCapture!=0) NumSceneCapture = 0;
}
void ASceneCaptureCamera::Tick(const float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
@ -284,27 +330,48 @@ void ASceneCaptureCamera::WritePixels(float DeltaTime) const
UE_LOG(LogCarla, Error, TEXT("SceneCaptureCamera: Missing render texture"));
return ;
}
const uint32 num_bytes_per_pixel = 4; // PF_R8G8B8A8
const uint32 width = texture->GetSizeX();
uint32 height = texture->GetSizeY();
uint32 stride;
uint8 *src = reinterpret_cast<uint8*>(RHILockTexture2D(texture, 0, RLM_ReadOnly, stride, false));
const uint32 height = texture->GetSizeY();
const uint32 dest_stride = width * height * num_bytes_per_pixel;
uint32 src_stride;
uint8 *src = reinterpret_cast<uint8*>(RHILockTexture2D(texture, 0, RLM_ReadOnly, src_stride, false));
struct {
uint32 Width;
uint32 Height;
uint32 Type;
float FOV;
} ImageHeader = {
SizeX,
SizeY,
width,
height,
PostProcessEffect::ToUInt(PostProcessEffect),
CaptureComponent2D->FOVAngle
};
FSensorDataView DataView(
std::unique_ptr<uint8[]> dest = nullptr;
//Direct 3D uses additional rows in the buffer,so we need check the result stride from the lock:
if(IsD3DPlatform(GMaxRHIShaderPlatform,false) && (dest_stride!=src_stride))
{
const uint32 copy_row_stride = width * num_bytes_per_pixel;
dest = std::make_unique<uint8[]>(dest_stride);
// Copy per row
uint8* dest_row = dest.get();
uint8* src_row = src;
for (uint32 Row = 0; Row < height; ++Row)
{
FMemory::Memcpy(dest_row, src_row, copy_row_stride);
dest_row += copy_row_stride;
src_row += src_stride;
}
src = dest.get();
}
const FSensorDataView DataView(
GetId(),
FReadOnlyBufferView{reinterpret_cast<const void *>(&ImageHeader), sizeof(ImageHeader)},
FReadOnlyBufferView{src,stride*height}
FReadOnlyBufferView{src,dest_stride}
);
WriteSensorData(DataView);
RHIUnlockTexture2D(texture, 0, false);
}

View File

@ -37,7 +37,7 @@ protected:
public:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual void Tick(float DeltaSeconds) override;
uint32 GetImageSizeX() const
@ -68,7 +68,9 @@ public:
void Set(const UCameraDescription &CameraDescription);
bool ReadPixels(TArray<FColor> &BitMap) const;
protected:
static uint32 NumSceneCapture;
private:
///Read the camera buffer and write it to the client with no lock of the resources (for Vulkan API)
@ -97,7 +99,7 @@ private:
UDrawFrustumComponent* DrawFrustum;
/** Render target necessary for scene capture */
UPROPERTY(Transient)
UPROPERTY()
UTextureRenderTarget2D* CaptureRenderTarget;
/** Scene capture component. */

View File

@ -12,7 +12,7 @@
ASceneCaptureToDiskCamera::ASceneCaptureToDiskCamera(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer),
SaveToFolder(FPaths::Combine(FPaths::ProjectSavedDir(), "SceneCaptures")),
SaveToFolder(*FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("SceneCaptures"))),
FileName("capture_%05d.png") {}
void ASceneCaptureToDiskCamera::BeginPlay()

View File

@ -122,10 +122,7 @@ static void LoadSettingsFromConfig(
// QualitySettings.
FString sQualityLevel;
ConfigFile.GetString(S_CARLA_QUALITYSETTINGS, TEXT("QualityLevel"), sQualityLevel);
if(!Settings.SetQualitySettingsLevel(UQualitySettings::FromString(sQualityLevel)))
{
//error
}
Settings.SetQualitySettingsLevel(UQualitySettings::FromString(sQualityLevel));
// Sensors.
FString Sensors;
@ -176,17 +173,9 @@ FString UQualitySettings::ToString(EQualitySettingsLevel QualitySettingsLevel)
return ptr->GetNameStringByIndex(static_cast<int32>(QualitySettingsLevel));
}
bool UCarlaSettings::SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel)
void UCarlaSettings::SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel)
{
if(newQualityLevel==EQualitySettingsLevel::None)
{
UE_LOG(LogCarla ,Warning, TEXT("Quality Settings Level not set!"));
return false;
}
QualitySettingsLevel = newQualityLevel;
return true;
}
void UCarlaSettings::LoadSettings()

View File

@ -5,13 +5,11 @@
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "Engine/StaticMesh.h"
#include "WeatherDescription.h"
#include "UObject/NoExportTypes.h"
#include "CarlaSettings.generated.h"
UENUM(BlueprintType)
enum class EQualitySettingsLevel : uint8
{
@ -42,7 +40,7 @@ public:
};
class USensorDescription;
struct FStaticMaterial;
/** Global settings for CARLA.
* Setting object used to hold both config settings and editable ones in one place
* To ensure the settings are saved to the specified config file make sure to add
@ -57,12 +55,12 @@ public:
/**
* Sets the new quality settings level and make changes in the game related to it.
* Returns the result of the operation.
* @note This will not apply the quality settings. Use ApplyQualitySettings functions instead
* @param newQualityLevel Store the new quality
*/
UFUNCTION(BlueprintCallable, Category="CARLA Settings")
bool SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel);
void SetQualitySettingsLevel(EQualitySettingsLevel newQualityLevel);
/** @return current quality settings level (could not be applied yet) */
UFUNCTION(BlueprintCallable, Category="CARLA Settings")
EQualitySettingsLevel GetQualitySettingsLevel() const { return QualitySettingsLevel; }

View File

@ -1,5 +1,5 @@
#include "Carla.h"
#include "Engine/World.h"
#include "Game/CarlaGameModeBase.h"
#include "Settings/CarlaSettings.h"
#include "CarlaSettingsDelegate.h"
@ -10,6 +10,7 @@
#include "Engine/StaticMesh.h"
#include "Engine/PostProcessVolume.h"
#include "UObjectIterator.h"
#include "Async.h"
///quality settings configuration between runs
EQualitySettingsLevel UCarlaSettingsDelegate::AppliedLowPostResetQualitySettingsLevel = EQualitySettingsLevel::Epic;
@ -21,8 +22,7 @@ UCarlaSettingsDelegate::UCarlaSettingsDelegate() :
void UCarlaSettingsDelegate::Reset()
{
LaunchEpicQualityCommands(GetLocalWorld());
AppliedLowPostResetQualitySettingsLevel = EQualitySettingsLevel::Epic;
AppliedLowPostResetQualitySettingsLevel = EQualitySettingsLevel::None;
}
void UCarlaSettingsDelegate::RegisterSpawnHandler(UWorld *InWorld)
@ -62,7 +62,8 @@ void UCarlaSettingsDelegate::ApplyQualitySettingsLevelPostRestart()
{
CheckCarlaSettings(nullptr);
UWorld *InWorld = CarlaSettings->GetWorld();
EQualitySettingsLevel QualitySettingsLevel = CarlaSettings->GetQualitySettingsLevel();
EQualitySettingsLevel QualitySettingsLevel = CarlaSettings->GetQualitySettingsLevel();
if(AppliedLowPostResetQualitySettingsLevel==QualitySettingsLevel) return;
switch(QualitySettingsLevel)
@ -70,7 +71,7 @@ void UCarlaSettingsDelegate::ApplyQualitySettingsLevelPostRestart()
case EQualitySettingsLevel::Low:
{
//execute tweaks for quality
LaunchLowQualityCommands(InWorld);
LaunchLowQualityCommands(InWorld);
//iterate all directional lights, deactivate shadows
SetAllLights(InWorld,CarlaSettings->LowLightFadeDistance,false,true);
//Set all the roads the low quality materials
@ -181,45 +182,49 @@ void UCarlaSettingsDelegate::LaunchLowQualityCommands(UWorld * world) const
void UCarlaSettingsDelegate::SetAllRoads(UWorld* world, const float max_draw_distance, const TArray<FStaticMaterial> &road_pieces_materials) const
{
TArray<AActor*> actors;
UGameplayStatics::GetAllActorsWithTag(world, UCarlaSettings::CARLA_ROAD_TAG,actors);
for(int32 i=0; i<actors.Num(); i++)
{
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
TArray<UActorComponent*> components = actors[i]->GetComponentsByClass(UStaticMeshComponent::StaticClass());
for(int32 j=0; j<components.Num(); j++)
{
UStaticMeshComponent* staticmeshcomponent = Cast<UStaticMeshComponent>(components[j]);
if(staticmeshcomponent)
{
staticmeshcomponent->bAllowCullDistanceVolume = (max_draw_distance>0);
staticmeshcomponent->bUseAsOccluder = false;
staticmeshcomponent->LDMaxDrawDistance = max_draw_distance;
staticmeshcomponent->CastShadow = (max_draw_distance==0);
if(road_pieces_materials.Num()>0)
{
TArray<FName> meshslotsnames = staticmeshcomponent->GetMaterialSlotNames();
for(int32 k=0; k<meshslotsnames.Num(); k++)
if(!world||!IsValid(world)||world->IsPendingKill()) return;
AsyncTask(ENamedThreads::GameThread, [=](){
if(!world||!IsValid(world)||world->IsPendingKill()) return;
TArray<AActor*> actors;
UGameplayStatics::GetAllActorsWithTag(world, UCarlaSettings::CARLA_ROAD_TAG,actors);
for(int32 i=0; i<actors.Num(); i++)
{
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
TArray<UActorComponent*> components = actors[i]->GetComponentsByClass(UStaticMeshComponent::StaticClass());
for(int32 j=0; j<components.Num(); j++)
{
UStaticMeshComponent* staticmeshcomponent = Cast<UStaticMeshComponent>(components[j]);
if(staticmeshcomponent)
{
staticmeshcomponent->bAllowCullDistanceVolume = (max_draw_distance>0);
staticmeshcomponent->bUseAsOccluder = false;
staticmeshcomponent->LDMaxDrawDistance = max_draw_distance;
staticmeshcomponent->CastShadow = (max_draw_distance==0);
if(road_pieces_materials.Num()>0)
{
const FName &slotname = meshslotsnames[k];
road_pieces_materials.ContainsByPredicate(
[staticmeshcomponent,slotname](const FStaticMaterial& material)
TArray<FName> meshslotsnames = staticmeshcomponent->GetMaterialSlotNames();
for(int32 k=0; k<meshslotsnames.Num(); k++)
{
if(material.MaterialSlotName.IsEqual(slotname))
const FName &slotname = meshslotsnames[k];
road_pieces_materials.ContainsByPredicate(
[staticmeshcomponent,slotname](const FStaticMaterial& material)
{
staticmeshcomponent->SetMaterial(
staticmeshcomponent->GetMaterialIndex(slotname),
material.MaterialInterface
);
return true;
} else return false;
});
if(material.MaterialSlotName.IsEqual(slotname))
{
staticmeshcomponent->SetMaterial(
staticmeshcomponent->GetMaterialIndex(slotname),
material.MaterialInterface
);
return true;
} else return false;
});
}
}
}
}
}
}
}
}
}
}); //,DELAY_TIME_TO_SET_ALL_ROADS, false);
}
void UCarlaSettingsDelegate::SetActorComponentsDrawDistance(AActor* actor, const float max_draw_distance) const
@ -243,20 +248,24 @@ void UCarlaSettingsDelegate::SetActorComponentsDrawDistance(AActor* actor, const
void UCarlaSettingsDelegate::SetAllActorsDrawDistance(UWorld* world, const float max_draw_distance) const
{
///@TODO: use semantics to grab all actors by type (vehicles,ground,people,props) and set different distances configured in the global properties
TArray<AActor*> actors;
#define _MAX_SCALE_SIZE 50.0f
//set the lower quality - max draw distance
UGameplayStatics::GetAllActorsOfClass(world, AActor::StaticClass(),actors);
for(int32 i=0; i<actors.Num(); i++)
{
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending() ||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_ROAD_TAG) ||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_SKY_TAG)
){
continue;
}
SetActorComponentsDrawDistance(actors[i], max_draw_distance);
}
if(!world||!IsValid(world)||world->IsPendingKill()) return;
AsyncTask(ENamedThreads::GameThread, [=](){
if(!world||!IsValid(world)||world->IsPendingKill()) return;
TArray<AActor*> actors;
#define _MAX_SCALE_SIZE 50.0f
//set the lower quality - max draw distance
UGameplayStatics::GetAllActorsOfClass(world, AActor::StaticClass(),actors);
for(int32 i=0; i<actors.Num(); i++)
{
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending() ||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_ROAD_TAG) ||
actors[i]->ActorHasTag(UCarlaSettings::CARLA_SKY_TAG)
){
continue;
}
SetActorComponentsDrawDistance(actors[i], max_draw_distance);
}
});
}
@ -266,12 +275,12 @@ void UCarlaSettingsDelegate::SetPostProcessEffectsEnabled(UWorld* world, const b
UGameplayStatics::GetAllActorsOfClass(world, APostProcessVolume::StaticClass(), actors);
for(int32 i=0; i<actors.Num(); i++)
{
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
APostProcessVolume* postprocessvolume = Cast<APostProcessVolume>(actors[i]);
if(postprocessvolume)
{
postprocessvolume->bEnabled = enabled;
}
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
APostProcessVolume* postprocessvolume = Cast<APostProcessVolume>(actors[i]);
if(postprocessvolume)
{
postprocessvolume->bEnabled = enabled;
}
}
}
@ -318,21 +327,26 @@ void UCarlaSettingsDelegate::LaunchEpicQualityCommands(UWorld* world) const
void UCarlaSettingsDelegate::SetAllLights(UWorld* world, const float max_distance_fade, const bool cast_shadows, const bool hide_non_directional) const
{
TArray<AActor*> actors;
UGameplayStatics::GetAllActorsOfClass(world, ALight::StaticClass(), actors);
for(int32 i=0;i<actors.Num();i++)
{
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
//tweak directional lights
ADirectionalLight* directionallight = Cast<ADirectionalLight>(actors[i]);
if(directionallight)
if(!world||!IsValid(world)||world->IsPendingKill()) return;
AsyncTask(ENamedThreads::GameThread, [=](){
if(!world||!IsValid(world)||world->IsPendingKill()) return;
TArray<AActor*> actors;
UGameplayStatics::GetAllActorsOfClass(world, ALight::StaticClass(), actors);
for(int32 i=0;i<actors.Num();i++)
{
directionallight->SetCastShadows(cast_shadows);
directionallight->SetLightFunctionFadeDistance(max_distance_fade);
continue;
if(!IsValid(actors[i]) || actors[i]->IsPendingKillPending()) continue;
//tweak directional lights
ADirectionalLight* directionallight = Cast<ADirectionalLight>(actors[i]);
if(directionallight)
{
directionallight->SetCastShadows(cast_shadows);
directionallight->SetLightFunctionFadeDistance(max_distance_fade);
continue;
}
//disable any other type of light
actors[i]->SetActorHiddenInGame(hide_non_directional);
}
//disable any other type of light
actors[i]->SetActorHiddenInGame(hide_non_directional);
}
});
}

View File

@ -5,12 +5,10 @@
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "CoreMinimal.h"
#include "Engine/World.h"
#include "CarlaSettingsDelegate.generated.h"
class UCarlaSettings;
/// Used to set settings for every actor that is spawned into the world.
UCLASS(BlueprintType)
class CARLA_API UCarlaSettingsDelegate : public UObject

View File

@ -11,10 +11,12 @@
#include "Vehicle/CarlaWheeledVehicle.h"
#include "Vehicle/WheeledVehicleAIController.h"
#include "Engine/PlayerStartPIE.h"
#include "EngineUtils.h"
#include "GameFramework/Character.h"
#include "GameFramework/PlayerStart.h"
#include "TimerManager.h"
#include "Kismet/GameplayStatics.h"
// =============================================================================
// -- Static local methods -----------------------------------------------------
@ -35,8 +37,7 @@ static AWheeledVehicleAIController *GetController(ACarlaWheeledVehicle *Vehicle)
// =============================================================================
// Sets default values
AVehicleSpawnerBase::AVehicleSpawnerBase(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
AVehicleSpawnerBase::AVehicleSpawnerBase(const FObjectInitializer& ObjectInitializer): Super(ObjectInitializer)
{
PrimaryActorTick.bCanEverTick = false;
}
@ -55,31 +56,71 @@ void AVehicleSpawnerBase::BeginPlay()
SpawnPoints.Add(*It);
}
UE_LOG(LogCarla, Log, TEXT("Found %d positions for spawning vehicles"), SpawnPoints.Num());
UE_LOG(LogCarla, Log, TEXT("Found %d PlayerStart positions for spawning vehicles"), SpawnPoints.Num());
if (SpawnPoints.Num() < NumberOfVehicles) {
bSpawnVehicles = false;
UE_LOG(LogCarla, Error, TEXT("We don't have enough spawn points for vehicles!"));
if (SpawnPoints.Num() < NumberOfVehicles && SpawnPoints.Num()>0)
{
UE_LOG(LogCarla, Warning, TEXT("We don't have enough spawn points (PlayerStart) for vehicles!"));
if(SpawnPoints.Num()==0)
{
UE_LOG(LogCarla, Error, TEXT("At least one spawn point (PlayerStart) is needed to spawn vehicles!"));
} else
{
UE_LOG(LogCarla, Log,
TEXT("To cover the %d vehicles to spawn after beginplay, it will spawn one new vehicle each %f seconds"),
NumberOfVehicles - SpawnPoints.Num(),
TimeBetweenSpawnAttemptsAfterBegin
)
;
}
}
if(NumberOfVehicles==0||SpawnPoints.Num()==0) bSpawnVehicles = false;
if (bSpawnVehicles) {
const int32 MaximumNumberOfAttempts = 4 * NumberOfVehicles;
if (bSpawnVehicles)
{
GetRandomEngine()->Shuffle(SpawnPoints);
const int32 MaximumNumberOfAttempts = SpawnPoints.Num();
int32 NumberOfAttempts = 0;
while ((NumberOfVehicles > Vehicles.Num()) && (NumberOfAttempts < MaximumNumberOfAttempts)) {
// Try to spawn one vehicle.
TryToSpawnRandomVehicle();
while ((NumberOfVehicles > Vehicles.Num()) && (NumberOfAttempts < MaximumNumberOfAttempts))
{
SpawnVehicleAtSpawnPoint(*SpawnPoints[NumberOfAttempts]);
++NumberOfAttempts;
}
if (NumberOfVehicles > Vehicles.Num()) {
if (NumberOfAttempts > NumberOfVehicles)
{
UE_LOG(LogCarla, Error, TEXT("Requested %d vehicles, but we were only able to spawn %d"), NumberOfVehicles, Vehicles.Num());
} else
{
if(NumberOfAttempts == NumberOfVehicles)
{
UE_LOG(LogCarla, Log, TEXT("Spawned all %d vehicles"), NumberOfAttempts);
} else
{
UE_LOG(LogCarla, Log,
TEXT("Starting the timer to spawn the other %d vehicles, one per %f seconds"),
NumberOfVehicles - NumberOfAttempts,
TimeBetweenSpawnAttemptsAfterBegin
);
GetWorld()->GetTimerManager().SetTimer(AttemptTimerHandle,this, &AVehicleSpawnerBase::SpawnVehicleAttempt, TimeBetweenSpawnAttemptsAfterBegin,false,-1);
}
}
}
}
void AVehicleSpawnerBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
GetWorld()->GetTimerManager().ClearAllTimersForObject(this);
}
void AVehicleSpawnerBase::SetNumberOfVehicles(const int32 Count)
{
if (Count > 0) {
if (Count > 0)
{
bSpawnVehicles = true;
NumberOfVehicles = Count;
} else {
@ -90,7 +131,8 @@ void AVehicleSpawnerBase::SetNumberOfVehicles(const int32 Count)
void AVehicleSpawnerBase::TryToSpawnRandomVehicle()
{
auto SpawnPoint = GetRandomSpawnPoint();
if (SpawnPoint != nullptr) {
if (SpawnPoint != nullptr)
{
SpawnVehicleAtSpawnPoint(*SpawnPoint);
} else {
UE_LOG(LogCarla, Error, TEXT("Unable to find spawn point"));
@ -102,11 +144,13 @@ void AVehicleSpawnerBase::SpawnVehicleAtSpawnPoint(
{
ACarlaWheeledVehicle *Vehicle;
SpawnVehicle(SpawnPoint.GetActorTransform(), Vehicle);
if ((Vehicle != nullptr) && !Vehicle->IsPendingKill()) {
if ((Vehicle != nullptr) && !Vehicle->IsPendingKill())
{
Vehicle->AIControllerClass = AWheeledVehicleAIController::StaticClass();
Vehicle->SpawnDefaultController();
auto Controller = GetController(Vehicle);
if (Controller != nullptr) { // Sometimes fails...
if (Controller != nullptr)
{ // Sometimes fails...
Controller->GetRandomEngine()->Seed(GetRandomEngine()->GenerateSeed());
Controller->SetRoadMap(GetRoadMap());
Controller->SetAutopilot(true);
@ -118,6 +162,38 @@ void AVehicleSpawnerBase::SpawnVehicleAtSpawnPoint(
}
}
void AVehicleSpawnerBase::SpawnVehicleAttempt()
{
if(Vehicles.Num()>=NumberOfVehicles)
{
UE_LOG(LogCarla, Log, TEXT("All vehicles spawned correctly"));
return;
}
APlayerStart* spawnpoint = GetRandomSpawnPoint();
APawn* playerpawn = UGameplayStatics::GetPlayerPawn(GetWorld(),0);
const float DistanceToPlayer = playerpawn&&spawnpoint? FVector::Distance(playerpawn->GetActorLocation(),spawnpoint->GetActorLocation()):0.0f;
float NextTime = TimeBetweenSpawnAttemptsAfterBegin;
if(DistanceToPlayer>DistanceToPlayerBetweenSpawnAttemptsAfterBegin)
{
SpawnVehicleAtSpawnPoint(*spawnpoint);
} else
{
NextTime /= 2.0f;
}
if(Vehicles.Num()<NumberOfVehicles)
{
auto &timemanager = GetWorld()->GetTimerManager();
if(AttemptTimerHandle.IsValid()) timemanager.ClearTimer(AttemptTimerHandle);
timemanager.SetTimer(AttemptTimerHandle,this, &AVehicleSpawnerBase::SpawnVehicleAttempt,NextTime,false,-1);
} else
{
UE_LOG(LogCarla, Log, TEXT("Last vehicle spawned correctly"));
}
}
APlayerStart *AVehicleSpawnerBase::GetRandomSpawnPoint()
{
return (SpawnPoints.Num() > 0 ? GetRandomEngine()->PickOne(SpawnPoints) : nullptr);

View File

@ -28,6 +28,9 @@ protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called when the actor is removed from the level
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UFUNCTION(BlueprintImplementableEvent)
void SpawnVehicle(const FTransform &SpawnTransform, ACarlaWheeledVehicle *&SpawnedCharacter);
@ -57,6 +60,9 @@ public:
{
return RoadMap;
}
/** Function called to spawn another vehicle when there is not enough spawn points in the beginplay */
UFUNCTION(Category = "Vehicle Spawner", BlueprintCallable)
void SpawnVehicleAttempt();
protected:
@ -65,7 +71,7 @@ protected:
void SpawnVehicleAtSpawnPoint(const APlayerStart &SpawnPoint);
UPROPERTY()
URoadMap *RoadMap;
URoadMap *RoadMap = nullptr;
/** If false, no walker will be spawned. */
UPROPERTY(Category = "Vehicle Spawner", EditAnywhere)
@ -75,9 +81,22 @@ protected:
UPROPERTY(Category = "Vehicle Spawner", EditAnywhere, meta = (EditCondition = bSpawnVehicles, ClampMin = "1"))
int32 NumberOfVehicles = 10;
UPROPERTY(Category = "Vechicle Spawner", VisibleAnywhere, AdvancedDisplay)
UPROPERTY(Category = "Vehicle Spawner", VisibleAnywhere, AdvancedDisplay)
TArray<APlayerStart *> SpawnPoints;
UPROPERTY(Category = "Vehicle Spawner", BlueprintReadOnly, VisibleAnywhere, AdvancedDisplay)
TArray<ACarlaWheeledVehicle *> Vehicles;
/** Time to spawn new vehicles after begin play if there was not enough spawn points at the moment */
UPROPERTY(Category = "Vehicle Spawner", BlueprintReadWrite, EditAnywhere, meta = (ClampMin = "0.1", ClampMax = "1000.0", UIMin = "0.1", UIMax = "1000.0"))
float TimeBetweenSpawnAttemptsAfterBegin = 3.0f;
/** Min Distance to the player vehicle to validate a spawn point location for the next vehicle spawn attempt */
UPROPERTY(Category = "Vehicle Spawner", BlueprintReadWrite, EditAnywhere, meta = (ClampMin = "10", ClampMax = "10000", UIMin = "10", UIMax = "10000"))
float DistanceToPlayerBetweenSpawnAttemptsAfterBegin = 5000;
private:
/** Time handler to spawn more vehicles in the case we could not do it in the beginplay */
FTimerHandle AttemptTimerHandle;
};

View File

@ -10,7 +10,6 @@
#include "Navigation/CrowdFollowingComponent.h"
#include "Perception/AIPerceptionComponent.h"
#include "Perception/AISenseConfig_Sight.h"
#include "Perception/AISense_Sight.h"
#include "WheeledVehicle.h"
#include "WheeledVehicleMovementComponent.h"
@ -27,8 +26,8 @@ static constexpr float UPDATE_TIME_IN_SECONDS = 0.6f;
static constexpr float PREVISION_TIME_IN_SECONDS = 5.0f;
static constexpr float WALKER_SIGHT_RADIUS = 500.0f;
static constexpr float WALKER_SPEED_DAMPING = 4.0f;
static constexpr float WALKER_PERIPHERAL_VISION_ANGLE_IN_DEGREES = 155.0f;
static constexpr float WALKER_MAX_TIME_PAUSED = 10.0f;
static constexpr float WALKER_PERIPHERAL_VISION_ANGLE_IN_DEGREES = 130.0f;
static constexpr float WALKER_MAX_TIME_PAUSED = 5.0f;
static constexpr float VEHICLE_SAFETY_RADIUS = 600.0f;
@ -176,11 +175,13 @@ void AWalkerAIController::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
TimeInState+=DeltaSeconds;
if (Status != EWalkerStatus::RunOver) {
if (Status != EWalkerStatus::RunOver)
{
switch (GetMoveStatus())
{
case EPathFollowingStatus::Idle:
case EPathFollowingStatus::Waiting:
default: break;
case EPathFollowingStatus::Idle:
//case EPathFollowingStatus::Waiting: //<-- incomplete path
LOG_AI_WALKER(Warning, "is stuck!");
ChangeStatus(EWalkerStatus::Stuck);
break;
@ -190,7 +191,8 @@ void AWalkerAIController::Tick(float DeltaSeconds)
TryResumeMovement();
}
break;
};
};
}
}
@ -225,7 +227,7 @@ void AWalkerAIController::OnMoveCompleted(
ChangeStatus(EWalkerStatus::MoveCompleted);
}
void AWalkerAIController::SenseActors(const TArray<AActor *> Actors)
void AWalkerAIController::SenseActors(TArray<AActor *> Actors)
{
const auto *aPawn = GetPawn();
if ((Status == EWalkerStatus::Moving) &&

View File

@ -54,6 +54,9 @@ public:
UFUNCTION(BlueprintCallable)
void TrySetMovement(bool paused);
UFUNCTION(BlueprintCallable)
float GetTimeInState() const { return TimeInState; }
private:
void ChangeStatus(EWalkerStatus status);
void TryResumeMovement();
@ -68,6 +71,6 @@ private:
UPROPERTY(VisibleAnywhere)
EWalkerStatus Status = EWalkerStatus::Unknown;
/** Continous time in the same EWalkerStatus */
float TimeInState=0.0f;
};

View File

@ -10,10 +10,10 @@
#include "Util/RandomEngine.h"
#include "Walker/WalkerAIController.h"
#include "Walker/WalkerSpawnPoint.h"
#include "Components/BoxComponent.h"
#include "EngineUtils.h"
#include "GameFramework/Character.h"
#include "Kismet/KismetSystemLibrary.h"
// =============================================================================
// -- Static local methods -----------------------------------------------------
@ -78,14 +78,19 @@ void AWalkerSpawnerBase::BeginPlay()
SpawnPoints.Add(SpawnPoint);
}
}
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
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());
#endif
if (SpawnPoints.Num() < 2) {
bSpawnWalkers = false;
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Error, TEXT("We don't have enough spawn points for walkers!"));
#endif
} else if (BeginSpawnPoints.Num() < NumberOfWalkers) {
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Warning, TEXT("Requested %d walkers, but we only have %d spawn points. Some will fail to spawn."), NumberOfWalkers, BeginSpawnPoints.Num());
#endif
}
GetRandomEngine()->Shuffle(BeginSpawnPoints);
@ -97,7 +102,9 @@ void AWalkerSpawnerBase::BeginPlay()
++Count;
}
}
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Log, TEXT("Spawned %d walkers at begin play."), Count);
#endif
}
}
@ -110,45 +117,139 @@ void AWalkerSpawnerBase::Tick(float DeltaTime)
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];
const auto Status = GetWalkerStatus(Walker);
if ((Status == EWalkerStatus::MoveCompleted) ||
(Status == EWalkerStatus::Invalid) ||
(Status == EWalkerStatus::RunOver)) {
WalkersBlackList.RemoveAtSwap(Index);
if ((Walker != nullptr) && (Status != EWalkerStatus::RunOver)) {
Walker->Destroy();
if (WalkersBlackList.Num() > 0)
{
CurrentBlackWalkerIndexToCheck = ++CurrentBlackWalkerIndexToCheck % WalkersBlackList.Num();
ACharacter* BlackListedWalker = WalkersBlackList[CurrentBlackWalkerIndexToCheck];
AWalkerAIController* controller = BlackListedWalker!=nullptr?Cast<AWalkerAIController>(BlackListedWalker->GetController()):nullptr;
if(BlackListedWalker != nullptr && controller!=nullptr && IsValid(BlackListedWalker))
{
const auto Status = GetWalkerStatus(BlackListedWalker);
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Log, TEXT("Watching walker %s with state %d"), *UKismetSystemLibrary::GetDisplayName(BlackListedWalker), (int)Status);
#endif
switch(Status)
{
case EWalkerStatus::RunOver:{
//remove from list and wait for auto-destroy
WalkersBlackList.RemoveAtSwap(CurrentBlackWalkerIndexToCheck);
break;
}
case EWalkerStatus::MoveCompleted:
{
BlackListedWalker->Destroy();
break;
}
default: {
switch(controller->GetMoveStatus())
{
case EPathFollowingStatus::Idle:
if(!TrySetDestination(*BlackListedWalker))
{
if(!SetRandomWalkerDestination(BlackListedWalker))
{
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla,Error,TEXT("Could not set a random destination to walker %s"),*UKismetSystemLibrary::GetDisplayName(BlackListedWalker));
#endif
}
}
break;
case EPathFollowingStatus::Waiting:
//incomplete path
break;
case EPathFollowingStatus::Paused:
//waiting for blueprint code
break;
case EPathFollowingStatus::Moving:
if(BlackListedWalker->GetVelocity().Size()>1.0f)
{
WalkersBlackList.RemoveAtSwap(CurrentBlackWalkerIndexToCheck);
Walkers.Add(BlackListedWalker);
}
break;
default: break;
}
break;
}
}
}
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Log, TEXT("New state for walker %s : %d"), *UKismetSystemLibrary::GetDisplayName(BlackListedWalker), (int)GetWalkerStatus(BlackListedWalker));
#endif
}
}
if (Walkers.Num() > 0) {
if (Walkers.Num() > 0)
{
// Check one walker, if fails black-list it or kill it.
const int32 Index = (++CurrentIndexToCheck % Walkers.Num());
auto Walker = Walkers[Index];
const auto Status = GetWalkerStatus(Walker);
if ((Status == EWalkerStatus::MoveCompleted) ||
(Status == EWalkerStatus::Invalid) ||
(Status == EWalkerStatus::RunOver)) {
// Kill it.
Walkers.RemoveAtSwap(Index);
// If it was run over will self-destroy.
if ((Walker != nullptr) && (Status != EWalkerStatus::RunOver)) {
Walker->Destroy();
}
} else if (Status == EWalkerStatus::Stuck) {
// Black-list it.
TrySetDestination(*Walker);
WalkersBlackList.Add(Walker);
Walkers.RemoveAtSwap(Index);
CurrentWalkerIndexToCheck = ++CurrentWalkerIndexToCheck % Walkers.Num();
auto Walker = Walkers[CurrentWalkerIndexToCheck];
if(Walker == nullptr || !IsValid(Walker))
{
Walkers.RemoveAtSwap(CurrentWalkerIndexToCheck);
} else {
const auto Status = GetWalkerStatus(Walker);
switch (Status)
{
default:
case EWalkerStatus::Paused:
case EWalkerStatus::Unknown:
break;
case EWalkerStatus::RunOver: {
Walkers.RemoveAtSwap(CurrentWalkerIndexToCheck);
break;
}
case EWalkerStatus::MoveCompleted:
Walker->Destroy();
break;
case EWalkerStatus::Invalid:
case EWalkerStatus::Stuck:
{
SetRandomWalkerDestination(Walker);
// Black-list it and wait for this walker to move
WalkersBlackList.Add(Walker);
Walkers.RemoveAtSwap(CurrentWalkerIndexToCheck);
break;
}
}
}
}
}
bool AWalkerSpawnerBase::SetRandomWalkerDestination(ACharacter *Walker)
{
const auto &DestinationPoint = GetRandomSpawnPoint();
auto Controller = GetController(Walker);
if(!Controller) {
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Warning, TEXT("AWalkerSpawnerBase::SetRandomWalkerDestination: Walker %s has no controller"),
*UKismetSystemLibrary::GetDisplayName(Walker)
);
#endif
return false;
}
const EPathFollowingRequestResult::Type request_result = Controller->MoveToLocation(DestinationPoint.GetActorLocation(),-1.0f,false,true,true,true,nullptr,true);
switch(request_result)
{
case EPathFollowingRequestResult::Type::Failed:
{
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Warning, TEXT("AWalkerSpawnerBase::SetRandomWalkerDestination: Bad destination point %s"),
*UKismetSystemLibrary::GetDisplayName(&DestinationPoint)
);
#endif
return false;
}
case EPathFollowingRequestResult::Type::AlreadyAtGoal:{
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(LogCarla, Log, TEXT("AWalkerSpawnerBase::SetRandomWalkerDestination already in destination, generating new location"));
#endif
return SetRandomWalkerDestination(Walker);
}
default: case EPathFollowingRequestResult::Type::RequestSuccessful: return true;
}
}
// =============================================================================
// -- Other member functions ---------------------------------------------------
// =============================================================================
@ -205,7 +306,10 @@ bool AWalkerSpawnerBase::TryToSpawnWalkerAt(const AWalkerSpawnPointBase &SpawnPo
// Add walker and set destination.
Walkers.Add(Walker);
Controller->MoveToLocation(Destination);
if (Controller->MoveToLocation(Destination,-1.0f,false,true,true,true,nullptr,true)!=EPathFollowingRequestResult::Type::RequestSuccessful)
{
SetRandomWalkerDestination(Walker);
}
return true;
}
@ -214,15 +318,22 @@ bool AWalkerSpawnerBase::TrySetDestination(ACharacter &Walker)
// Try to retrieve controller.
auto Controller = GetController(&Walker);
if (Controller == nullptr) {
UE_LOG(LogCarla, Warning, TEXT("Could not get valid controller for walker: %s"), *Walker.GetName());
return false;
}
// Try find destination.
FVector Destination;
if (!TryGetValidDestination(Walker.GetActorLocation(), Destination)) {
#ifdef CARLA_AI_WALKERS_EXTRA_LOG
UE_LOG(
LogCarla, Warning,
TEXT("Could not get a new destiny: %s for walker: %s"),
*Destination.ToString(), *Walker.GetName()
);
#endif
return false;
}
Controller->MoveToLocation(Destination);
return true;
return Controller->MoveToLocation(Destination,-1.0f,false,true,true,true,nullptr,true)==EPathFollowingRequestResult::RequestSuccessful;
}

View File

@ -45,6 +45,7 @@ public:
virtual void Tick(float DeltaTime) override;
/// @}
// ===========================================================================
/// @name Blueprintable functions
@ -87,6 +88,7 @@ private:
bool TrySetDestination(ACharacter &Walker);
bool SetRandomWalkerDestination(ACharacter * Walker);
/// @}
private:
@ -116,5 +118,7 @@ private:
UPROPERTY(Category = "Walker Spawner", VisibleAnywhere, AdvancedDisplay)
TArray<ACharacter *> WalkersBlackList;
uint32 CurrentIndexToCheck = 0u;
uint32 CurrentWalkerIndexToCheck = 0u;
uint32 CurrentBlackWalkerIndexToCheck = 0u;
};