From 6ad6ee873e6b6ebde89af0d5bfb6ab4b7a21d5df Mon Sep 17 00:00:00 2001 From: nsubiron Date: Wed, 17 May 2017 17:23:27 +0100 Subject: [PATCH 01/15] Forgot to refresh weather --- Source/Carla/Game/CarlaGameModeBase.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Carla/Game/CarlaGameModeBase.cpp b/Source/Carla/Game/CarlaGameModeBase.cpp index e916d68b4..c2c27fc1a 100644 --- a/Source/Carla/Game/CarlaGameModeBase.cpp +++ b/Source/Carla/Game/CarlaGameModeBase.cpp @@ -101,6 +101,7 @@ void ACarlaGameModeBase::BeginPlay() const auto &Weather = CarlaSettings.GetActiveWeatherDescription(); UE_LOG(LogCarla, Log, TEXT("Changing weather settings to \"%s\""), *Weather.Name); DynamicWeather->SetWeatherDescription(Weather); + DynamicWeather->RefreshWeather(); } // Setup walkers. From b411eb6c0c0829ae7f322ea6e673b3136d0de2cc Mon Sep 17 00:00:00 2001 From: nsubiron Date: Thu, 18 May 2017 12:18:57 +0100 Subject: [PATCH 02/15] Fix some issues with the dynamic weather updates and add more settings to the mock controller --- Source/Carla/DynamicWeather.cpp | 10 +++---- Source/Carla/DynamicWeather.h | 2 -- Source/Carla/Game/CarlaGameInstance.cpp | 7 +++-- Source/Carla/Game/CarlaGameInstance.h | 4 ++- Source/Carla/Game/CarlaGameModeBase.cpp | 17 +++++++---- Source/Carla/Game/CarlaGameModeBase.h | 7 ++++- Source/Carla/Game/CarlaSettings.cpp | 4 +-- Source/Carla/Game/CarlaSettings.h | 11 +++++--- Source/Carla/Game/MockGameController.cpp | 28 +++++++++++++++++-- Source/Carla/Game/MockGameController.h | 7 +++++ .../Carla/Game/MockGameControllerSettings.h | 23 +++++++++++++++ 11 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 Source/Carla/Game/MockGameControllerSettings.h diff --git a/Source/Carla/DynamicWeather.cpp b/Source/Carla/DynamicWeather.cpp index faad95dcc..e98699d0d 100644 --- a/Source/Carla/DynamicWeather.cpp +++ b/Source/Carla/DynamicWeather.cpp @@ -68,12 +68,6 @@ ADynamicWeather::ADynamicWeather(const FObjectInitializer& ObjectInitializer) #endif // WITH_EDITORONLY_DATA } -void ADynamicWeather::OnConstruction(const FTransform &Transform) -{ - Super::OnConstruction(Transform); - Update(); -} - #if WITH_EDITOR void ADynamicWeather::PostEditChangeProperty(FPropertyChangedEvent &Event) @@ -82,6 +76,9 @@ void ADynamicWeather::PostEditChangeProperty(FPropertyChangedEvent &Event) const FName PropertyName = (Event.Property != NULL ? Event.Property->GetFName() : NAME_None); if (PropertyName == GET_MEMBER_NAME_CHECKED(ADynamicWeather, Weather)) { Update(); + } else if ((PropertyName == GET_MEMBER_NAME_CHECKED(ADynamicWeather, bSaveToConfigFile)) || + (PropertyName == GET_MEMBER_NAME_CHECKED(ADynamicWeather, bLoadFromConfigFile))) { + // Do nothing. } else { AdjustSunPositionBasedOnActorRotation(); } @@ -97,6 +94,7 @@ void ADynamicWeather::PostEditChangeProperty(FPropertyChangedEvent &Event) bLoadFromConfigFile = false; if (LoadFromConfigFile()) { UE_LOG(LogCarla, Log, TEXT("Weather \"%s\" loaded from config file"), *Weather.Name); + Update(); } else { UE_LOG(LogCarla, Error, TEXT("Error loading weather from config file")); } diff --git a/Source/Carla/DynamicWeather.h b/Source/Carla/DynamicWeather.h index 7340b7e77..bd6441628 100644 --- a/Source/Carla/DynamicWeather.h +++ b/Source/Carla/DynamicWeather.h @@ -20,8 +20,6 @@ public: ADynamicWeather(const FObjectInitializer& ObjectInitializer); - virtual void OnConstruction(const FTransform &Transform) override; - #if WITH_EDITOR virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; diff --git a/Source/Carla/Game/CarlaGameInstance.cpp b/Source/Carla/Game/CarlaGameInstance.cpp index 76372e34e..f65568698 100644 --- a/Source/Carla/Game/CarlaGameInstance.cpp +++ b/Source/Carla/Game/CarlaGameInstance.cpp @@ -16,7 +16,8 @@ UCarlaGameInstance::UCarlaGameInstance() { UCarlaGameInstance::~UCarlaGameInstance() {} -void UCarlaGameInstance::InitializeGameControllerIfNotPresent() +void UCarlaGameInstance::InitializeGameControllerIfNotPresent( + const FMockGameControllerSettings &MockControllerSettings) { if (GameController == nullptr) { if (CarlaSettings->bUseNetworking) { @@ -25,8 +26,8 @@ void UCarlaGameInstance::InitializeGameControllerIfNotPresent() CarlaSettings->WritePort, CarlaSettings->ReadPort); } else { - GameController = MakeUnique(); - UE_LOG(LogCarla, Warning, TEXT("Using mock CARLA controller")); + GameController = MakeUnique(MockControllerSettings); + UE_LOG(LogCarla, Log, TEXT("Using mock CARLA controller")); } } } diff --git a/Source/Carla/Game/CarlaGameInstance.h b/Source/Carla/Game/CarlaGameInstance.h index 837f3478c..bd768a904 100644 --- a/Source/Carla/Game/CarlaGameInstance.h +++ b/Source/Carla/Game/CarlaGameInstance.h @@ -7,6 +7,7 @@ #include "CarlaGameInstance.generated.h" class UCarlaSettings; +struct FMockGameControllerSettings; /// The game instance contains elements that must be kept alive in between /// levels. It is instantiate once per game. @@ -21,7 +22,8 @@ public: ~UCarlaGameInstance(); - void InitializeGameControllerIfNotPresent(); + void InitializeGameControllerIfNotPresent( + const FMockGameControllerSettings &MockControllerSettings); CarlaGameControllerBase &GetGameController() { diff --git a/Source/Carla/Game/CarlaGameModeBase.cpp b/Source/Carla/Game/CarlaGameModeBase.cpp index c2c27fc1a..19c4c747e 100644 --- a/Source/Carla/Game/CarlaGameModeBase.cpp +++ b/Source/Carla/Game/CarlaGameModeBase.cpp @@ -23,6 +23,7 @@ ACarlaGameModeBase::ACarlaGameModeBase(const FObjectInitializer& ObjectInitializ { PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.TickGroup = TG_PrePhysics; + bAllowTickBeforeBeginPlay = false; PlayerControllerClass = ACarlaVehicleController::StaticClass(); GameStateClass = ACarlaGameState::StaticClass(); @@ -43,7 +44,7 @@ void ACarlaGameModeBase::InitGame( checkf( GameInstance != nullptr, TEXT("GameInstance is not a UCarlaGameInstance, did you forget to set it in the project settings?")); - GameInstance->InitializeGameControllerIfNotPresent(); + GameInstance->InitializeGameControllerIfNotPresent(MockGameControllerSettings); GameController = &GameInstance->GetGameController(); GameController->Initialize(GameInstance->GetCarlaSettings()); GameInstance->GetCarlaSettings().LogSettings(); @@ -98,15 +99,21 @@ void ACarlaGameModeBase::BeginPlay() // Change weather. if (DynamicWeather != nullptr) { - const auto &Weather = CarlaSettings.GetActiveWeatherDescription(); - UE_LOG(LogCarla, Log, TEXT("Changing weather settings to \"%s\""), *Weather.Name); - DynamicWeather->SetWeatherDescription(Weather); - DynamicWeather->RefreshWeather(); + const auto *Weather = CarlaSettings.GetActiveWeatherDescription(); + if (Weather != nullptr) { + UE_LOG(LogCarla, Log, TEXT("Changing weather settings to \"%s\""), *Weather->Name); + DynamicWeather->SetWeatherDescription(*Weather); + DynamicWeather->RefreshWeather(); + } + } else { + UE_LOG(LogCarla, Error, TEXT("Missing dynamic weather actor!")); } // Setup walkers. if (WalkerSpawner != nullptr) { WalkerSpawner->SetNumberOfWalkers(CarlaSettings.NumberOfPedestrians); + } else { + UE_LOG(LogCarla, Error, TEXT("Missing walker spawner actor!")); } GameController->BeginPlay(); diff --git a/Source/Carla/Game/CarlaGameModeBase.h b/Source/Carla/Game/CarlaGameModeBase.h index 224dfc050..893c0ef9b 100644 --- a/Source/Carla/Game/CarlaGameModeBase.h +++ b/Source/Carla/Game/CarlaGameModeBase.h @@ -6,6 +6,7 @@ #include "AI/WalkerSpawnerBase.h" #include "CarlaGameControllerBase.h" #include "DynamicWeather.h" +#include "MockGameControllerSettings.h" #include "CarlaGameModeBase.generated.h" class APlayerStart; @@ -15,7 +16,7 @@ class UTaggerDelegate; /** * */ -UCLASS() +UCLASS(HideCategories=(ActorTick)) class CARLA_API ACarlaGameModeBase : public AGameModeBase { GENERATED_BODY() @@ -34,6 +35,10 @@ public: protected: + /** Used only when networking is disabled. */ + UPROPERTY(Category = "Mock CARLA Controller", EditAnywhere, BlueprintReadOnly, meta = (ExposeFunctionCategories = "Mock CARLA Controller")) + FMockGameControllerSettings MockGameControllerSettings; + /** The class of DynamicWeather to spawn. */ UPROPERTY(Category = "CARLA Classes", EditAnywhere, BlueprintReadOnly) TSubclassOf DynamicWeatherClass; diff --git a/Source/Carla/Game/CarlaSettings.cpp b/Source/Carla/Game/CarlaSettings.cpp index f5b55a08d..cedcd7b9a 100644 --- a/Source/Carla/Game/CarlaSettings.cpp +++ b/Source/Carla/Game/CarlaSettings.cpp @@ -90,9 +90,9 @@ static void LoadSettingsFromFile(const FString &FileName, UCarlaSettings &Settin Settings.WeatherDescriptions.Empty(); ADynamicWeather::LoadWeatherDescriptionsFromFile(Settings.WeatherDescriptions); check(Settings.WeatherDescriptions.Num() > 0); - if (static_cast(Settings.WeatherId) >= Settings.WeatherDescriptions.Num()) { + if (Settings.WeatherId >= Settings.WeatherDescriptions.Num()) { UE_LOG(LogCarla, Error, TEXT("Provided weather id %d cannot be found"), Settings.WeatherId); - Settings.WeatherId = 0u; + Settings.WeatherId = -1; } // SceneCapture. FString Cameras; diff --git a/Source/Carla/Game/CarlaSettings.h b/Source/Carla/Game/CarlaSettings.h index 0d62f107b..5ba1af7fb 100644 --- a/Source/Carla/Game/CarlaSettings.h +++ b/Source/Carla/Game/CarlaSettings.h @@ -22,9 +22,12 @@ public: /** Log settings values. */ void LogSettings() const; - const FWeatherDescription &GetActiveWeatherDescription() const + const FWeatherDescription *GetActiveWeatherDescription() const { - return WeatherDescriptions[WeatherId]; + if ((WeatherId > 0) && (WeatherId < WeatherDescriptions.Num())) { + return &WeatherDescriptions[WeatherId]; + } + return nullptr; } private: @@ -70,9 +73,9 @@ public: UPROPERTY(Category = "Level Settings", EditDefaultsOnly) uint32 NumberOfPedestrians = 15u; - /** Index of the weather setting to use. */ + /** Index of the weather setting to use. If negative, weather won't be changed. */ UPROPERTY(Category = "Level Settings", EditDefaultsOnly) - uint32 WeatherId = 0; + int32 WeatherId = -1; /** Available weather settings. */ UPROPERTY(Category = "Level Settings", EditDefaultsOnly) diff --git a/Source/Carla/Game/MockGameController.cpp b/Source/Carla/Game/MockGameController.cpp index 839de6494..fefd3a912 100644 --- a/Source/Carla/Game/MockGameController.cpp +++ b/Source/Carla/Game/MockGameController.cpp @@ -3,15 +3,37 @@ #include "Carla.h" #include "MockGameController.h" -void MockGameController::Initialize(UCarlaSettings & /*CarlaSettings*/) -{ +MockGameController::MockGameController(const FMockGameControllerSettings &Settings) : + Settings(Settings) {} +void MockGameController::Initialize(UCarlaSettings & CarlaSettings) +{ + if (Settings.bChangeWeatherOnBeginPlay && (CarlaSettings.WeatherDescriptions.Num() > 0)) { + static uint32 StaticIndex = 0u; + CarlaSettings.WeatherId = StaticIndex % CarlaSettings.WeatherDescriptions.Num(); + ++StaticIndex; + } else { + CarlaSettings.WeatherId = -1; + } + + if (Settings.bForceEnableSemanticSegmentation) { + CarlaSettings.bSemanticSegmentationEnabled = true; + } } APlayerStart *MockGameController::ChoosePlayerStart( const TArray &AvailableStartSpots) { - return AvailableStartSpots[FMath::RandRange(0, AvailableStartSpots.Num() - 1)]; + check(AvailableStartSpots.Num() > 0); + uint32 Index; + if (Settings.bRandomPlayerStart) { + Index = FMath::RandRange(0, AvailableStartSpots.Num() - 1); + } else { + static uint32 StaticIndex = 0u; + Index = StaticIndex % AvailableStartSpots.Num(); + ++StaticIndex; + } + return AvailableStartSpots[Index]; } void MockGameController::RegisterPlayer(AController &NewPlayer) diff --git a/Source/Carla/Game/MockGameController.h b/Source/Carla/Game/MockGameController.h index 2b95bcf1c..e86b65fc9 100644 --- a/Source/Carla/Game/MockGameController.h +++ b/Source/Carla/Game/MockGameController.h @@ -3,12 +3,15 @@ #pragma once #include "CarlaGameControllerBase.h" +#include "MockGameControllerSettings.h" /// Mocks the CARLA game controller class for testing purposes. class CARLA_API MockGameController : public CarlaGameControllerBase { public: + explicit MockGameController(const FMockGameControllerSettings &Settings); + virtual void Initialize(UCarlaSettings &CarlaSettings) override; virtual APlayerStart *ChoosePlayerStart(const TArray &AvailableStartSpots) override; @@ -18,4 +21,8 @@ public: virtual void BeginPlay() override; virtual void Tick(float DeltaSeconds) override; + +private: + + FMockGameControllerSettings Settings; }; diff --git a/Source/Carla/Game/MockGameControllerSettings.h b/Source/Carla/Game/MockGameControllerSettings.h new file mode 100644 index 000000000..bad622203 --- /dev/null +++ b/Source/Carla/Game/MockGameControllerSettings.h @@ -0,0 +1,23 @@ +// CARLA, Copyright (C) 2017 Computer Vision Center (CVC) + +#pragma once + +#include "MockGameControllerSettings.generated.h" + +USTRUCT(BlueprintType) +struct FMockGameControllerSettings +{ + GENERATED_USTRUCT_BODY() + + /** If true, weather will be changed every time we start the level. */ + UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller") + bool bChangeWeatherOnBeginPlay = true; + + /** If true, a random player start position will be chosen every time we start the level. */ + UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller") + bool bRandomPlayerStart = true; + + /** If true, semantic segmentation will be always enabled even if no camera needs it. */ + UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller") + bool bForceEnableSemanticSegmentation = false; +}; From 97885dfdb478e53b193be72627eb0dc085f2d39b Mon Sep 17 00:00:00 2001 From: nsubiron Date: Thu, 18 May 2017 17:00:54 +0100 Subject: [PATCH 03/15] Add an option for refreshing the weather automatically --- Source/Carla/DynamicWeather.cpp | 38 ++++++++++++++++++++++++--------- Source/Carla/DynamicWeather.h | 16 ++++++++++++-- 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/Source/Carla/DynamicWeather.cpp b/Source/Carla/DynamicWeather.cpp index e98699d0d..1bbdf98cf 100644 --- a/Source/Carla/DynamicWeather.cpp +++ b/Source/Carla/DynamicWeather.cpp @@ -68,6 +68,22 @@ ADynamicWeather::ADynamicWeather(const FObjectInitializer& ObjectInitializer) #endif // WITH_EDITORONLY_DATA } +void ADynamicWeather::OnConstruction(const FTransform &Transform) +{ + Super::OnConstruction(Transform); +#if WITH_EDITOR + Update(); +#endif // WITH_EDITOR +} + +void ADynamicWeather::BeginPlay() +{ + Super::BeginPlay(); +#if WITH_EDITOR + Update(); +#endif // WITH_EDITOR +} + #if WITH_EDITOR void ADynamicWeather::PostEditChangeProperty(FPropertyChangedEvent &Event) @@ -121,16 +137,6 @@ FVector ADynamicWeather::GetSunDirection() const return - SphericalCoords.SphericalToUnitCartesian(); } -void ADynamicWeather::Update() -{ - // Modify this actor's rotation according to Sun position. - if (!SetActorRotation(FQuat(GetSunDirection().Rotation()), ETeleportType::None)) { - UE_LOG(LogCarla, Warning, TEXT("Unable to rotate actor")); - } - - RefreshWeather(); -} - void ADynamicWeather::AdjustSunPositionBasedOnActorRotation() { const FVector Direction = - GetActorQuat().GetForwardVector(); @@ -141,6 +147,18 @@ void ADynamicWeather::AdjustSunPositionBasedOnActorRotation() #if WITH_EDITOR +void ADynamicWeather::Update() +{ + // Modify this actor's rotation according to Sun position. + if (!SetActorRotation(FQuat(GetSunDirection().Rotation()), ETeleportType::None)) { + UE_LOG(LogCarla, Warning, TEXT("Unable to rotate actor")); + } + + if (bRefreshAutomatically) { + RefreshWeather(); + } +} + bool ADynamicWeather::LoadFromConfigFile() { FString FileName; diff --git a/Source/Carla/DynamicWeather.h b/Source/Carla/DynamicWeather.h index bd6441628..e4b57f797 100644 --- a/Source/Carla/DynamicWeather.h +++ b/Source/Carla/DynamicWeather.h @@ -20,6 +20,10 @@ public: ADynamicWeather(const FObjectInitializer& ObjectInitializer); + virtual void OnConstruction(const FTransform &Transform) override; + + virtual void BeginPlay() override; + #if WITH_EDITOR virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; @@ -47,12 +51,12 @@ public: private: - void Update(); - void AdjustSunPositionBasedOnActorRotation(); #if WITH_EDITOR + void Update(); + bool LoadFromConfigFile(); bool SaveToConfigFile() const; @@ -64,9 +68,17 @@ private: UPROPERTY() UArrowComponent *ArrowComponent; + /** If true, the weather is refreshed on construction and at begin play. + * Useful for editing the weather (Editor only). + */ + UPROPERTY(Category = "Weather Description", EditAnywhere) + bool bRefreshAutomatically = false; + + /** Load the section with the currently set name. */ UPROPERTY(Category = "Weather Description", EditAnywhere) bool bLoadFromConfigFile = false; + /** Save current settings to disk. */ UPROPERTY(Category = "Weather Description", EditAnywhere) bool bSaveToConfigFile = false; From 310b31a0f4d62db41e65ed1d98f4ea6ec09c8c30 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Thu, 18 May 2017 17:01:35 +0100 Subject: [PATCH 04/15] Add options to game mode for overriding CARLA settings in editor --- Source/Carla/Game/MockGameController.cpp | 9 +++++++ .../Carla/Game/MockGameControllerSettings.h | 25 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Source/Carla/Game/MockGameController.cpp b/Source/Carla/Game/MockGameController.cpp index fefd3a912..48012c774 100644 --- a/Source/Carla/Game/MockGameController.cpp +++ b/Source/Carla/Game/MockGameController.cpp @@ -8,6 +8,14 @@ MockGameController::MockGameController(const FMockGameControllerSettings &Settin void MockGameController::Initialize(UCarlaSettings & CarlaSettings) { +#ifdef WITH_EDITOR + if (Settings.bOverrideCarlaSettings) { + CarlaSettings.NumberOfVehicles = Settings.NumberOfVehicles; + CarlaSettings.NumberOfPedestrians = Settings.NumberOfPedestrians; + CarlaSettings.WeatherId = Settings.WeatherId; + } +#endif // WITH_EDITOR + if (Settings.bChangeWeatherOnBeginPlay && (CarlaSettings.WeatherDescriptions.Num() > 0)) { static uint32 StaticIndex = 0u; CarlaSettings.WeatherId = StaticIndex % CarlaSettings.WeatherDescriptions.Num(); @@ -33,6 +41,7 @@ APlayerStart *MockGameController::ChoosePlayerStart( Index = StaticIndex % AvailableStartSpots.Num(); ++StaticIndex; } + UE_LOG(LogCarla, Log, TEXT("Spawning player at player start %d/%d"), Index, AvailableStartSpots.Num()); return AvailableStartSpots[Index]; } diff --git a/Source/Carla/Game/MockGameControllerSettings.h b/Source/Carla/Game/MockGameControllerSettings.h index bad622203..a06a5a0d1 100644 --- a/Source/Carla/Game/MockGameControllerSettings.h +++ b/Source/Carla/Game/MockGameControllerSettings.h @@ -9,7 +9,10 @@ struct FMockGameControllerSettings { GENERATED_USTRUCT_BODY() - /** If true, weather will be changed every time we start the level. */ + /** If true, weather will be changed every time we start the level. + * + * Has precedence over options in "Override CARLA Settings". + */ UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller") bool bChangeWeatherOnBeginPlay = true; @@ -20,4 +23,24 @@ struct FMockGameControllerSettings /** If true, semantic segmentation will be always enabled even if no camera needs it. */ UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller") bool bForceEnableSemanticSegmentation = false; + +#if WITH_EDITORONLY_DATA + + /** Override available settings in CARLA Settings (Editor only). */ + UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller", meta = (DisplayName = "Override CARLA Settings")) + bool bOverrideCarlaSettings = false; + + /** Number of NPC vehicles to be spawned into the level. */ + UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller", meta = (EditCondition = "bOverrideCarlaSettings", ClampMin = 0)) + int32 NumberOfVehicles = 5; + + /** Number of NPC pedestrians to be spawned into the level. */ + UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller", meta = (EditCondition = "bOverrideCarlaSettings", ClampMin = 0)) + int32 NumberOfPedestrians = 15; + + /** Index of the weather setting to use. If negative, weather won't be changed. */ + UPROPERTY(EditAnywhere, Category = "Mock CARLA Controller", meta = (EditCondition = "bOverrideCarlaSettings")) + int32 WeatherId = -1; + +#endif // WITH_EDITORONLY_DATA }; From eed1497d067f17a37f5b19510d02ea0dd9a675d0 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Fri, 19 May 2017 15:27:06 +0100 Subject: [PATCH 05/15] Prepare for new release --- CHANGELOG.md | 13 +++++++++++++ Carla.uplugin | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b26a88bb..afbde3c37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +## CARLA 0.3.0 + + * Added basic dynamic weather functionality. + - Weather and sun light can be changed during game. + - Presets stored in config file CarlaWeather.ini. + * Add basic functionality to spawn pedestrians. + * Split road meshes for intersections and turns for better precission of the road map. + * Better debug for road map. + * Implemented collision count for other cars and pedestrians. + * Command line argument -carla-settings now accepts relative paths. + * Improved performance when semantic segmentation is disabled. + * Improved tagger system. + ## CARLA 0.2.4 * Fixed serialization of road map resulting in a huge map size. diff --git a/Carla.uplugin b/Carla.uplugin index e51103ee1..59594374d 100644 --- a/Carla.uplugin +++ b/Carla.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, "Version": 1, - "VersionName": "0.2.4", + "VersionName": "0.3.0", "FriendlyName": "CARLA", "Description": "", "Category": "Science", From 2d8e079a12e5504c5a003d84659a03203e2bb4b0 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Fri, 19 May 2017 16:03:59 +0100 Subject: [PATCH 06/15] Fix compilation warning --- Source/Carla/Game/MockGameController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Carla/Game/MockGameController.cpp b/Source/Carla/Game/MockGameController.cpp index 48012c774..3e47f7ac8 100644 --- a/Source/Carla/Game/MockGameController.cpp +++ b/Source/Carla/Game/MockGameController.cpp @@ -3,8 +3,8 @@ #include "Carla.h" #include "MockGameController.h" -MockGameController::MockGameController(const FMockGameControllerSettings &Settings) : - Settings(Settings) {} +MockGameController::MockGameController(const FMockGameControllerSettings &InSettings) : + Settings(InSettings) {} void MockGameController::Initialize(UCarlaSettings & CarlaSettings) { From 1ad8e76a6ea3e583213bee21ad0ede5998f5913d Mon Sep 17 00:00:00 2001 From: nsubiron Date: Fri, 19 May 2017 16:49:31 +0100 Subject: [PATCH 07/15] Update CarlaSettings.ini example --- Resources/Example.CarlaSettings.ini | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Resources/Example.CarlaSettings.ini b/Resources/Example.CarlaSettings.ini index 20810b9dc..4aa5a2582 100644 --- a/Resources/Example.CarlaSettings.ini +++ b/Resources/Example.CarlaSettings.ini @@ -14,6 +14,14 @@ WorldPort=2000 WritePort=2001 ReadPort=2002 +[CARLA/LevelSettings] +; Number of NPC vehicles to be spawned into the level. +NumberOfVehicles=5 +; Number of NPC pedestrians to be spawned into the level. +NumberOfPedestrians=15 +; Index of the weather presets to use. If negative, weather won't be changed. +WeatherId=-1 + [CARLA/SceneCapture] ; Names of the scene capture cameras to attach to the player, each of them ; should be defined in its own subsection. From 824264732d8203c76c794bb238b43d4a3687bb43 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Fri, 19 May 2017 16:50:24 +0100 Subject: [PATCH 08/15] Fix issues with Mock controller --- Source/Carla/Game/MockGameController.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/Carla/Game/MockGameController.cpp b/Source/Carla/Game/MockGameController.cpp index 3e47f7ac8..dead01937 100644 --- a/Source/Carla/Game/MockGameController.cpp +++ b/Source/Carla/Game/MockGameController.cpp @@ -8,7 +8,7 @@ MockGameController::MockGameController(const FMockGameControllerSettings &InSett void MockGameController::Initialize(UCarlaSettings & CarlaSettings) { -#ifdef WITH_EDITOR +#if WITH_EDITOR if (Settings.bOverrideCarlaSettings) { CarlaSettings.NumberOfVehicles = Settings.NumberOfVehicles; CarlaSettings.NumberOfPedestrians = Settings.NumberOfPedestrians; @@ -20,13 +20,13 @@ void MockGameController::Initialize(UCarlaSettings & CarlaSettings) static uint32 StaticIndex = 0u; CarlaSettings.WeatherId = StaticIndex % CarlaSettings.WeatherDescriptions.Num(); ++StaticIndex; - } else { - CarlaSettings.WeatherId = -1; } +#if WITH_EDITOR if (Settings.bForceEnableSemanticSegmentation) { CarlaSettings.bSemanticSegmentationEnabled = true; } +#endif // WITH_EDITOR } APlayerStart *MockGameController::ChoosePlayerStart( From 438756f57ef3afdfc20d025336980c89676d8a70 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Fri, 19 May 2017 17:41:15 +0100 Subject: [PATCH 09/15] Update release README --- Resources/RELEASE.README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Resources/RELEASE.README.md b/Resources/RELEASE.README.md index f9e1ab0f2..3704f9231 100644 --- a/Resources/RELEASE.README.md +++ b/Resources/RELEASE.README.md @@ -20,3 +20,32 @@ following [/Script/Engine.RendererSettings] r.CustomDepth=3 ``` + +Weather presets +--------------- + +To change the weather and sun light, set `WeatherId` in CarlaSettings.ini +from the following + + * 0 - Default + * 1 - ClearNoon + * 2 - CloudyNoon + * 3 - WetNoon + * 4 - WetCloudyNoon + * 5 - MidRainyNoon + * 6 - HardRainNoon + * 7 - SoftRainNoon + * 8 - ClearSunset + * 9 - CloudySunset + * 10 - WetSunset + * 11 - WetCloudySunset + * 12 - MidRainSunset + * 13 - HardRainSunset + * 14 - SoftRainSunset + +E.g., to choose the weather to be hard-rain at noon, add to CarlaSettings.ini + +``` +[CARLA/LevelSettings] +WeatherId=6 +``` From bf214c22a5b69bd3d2ad637f5a4aa1cd6af2ebb8 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Mon, 22 May 2017 08:43:11 +0100 Subject: [PATCH 10/15] Fix default weather was ignored --- Source/Carla/Game/CarlaSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Carla/Game/CarlaSettings.h b/Source/Carla/Game/CarlaSettings.h index 5ba1af7fb..935c751ce 100644 --- a/Source/Carla/Game/CarlaSettings.h +++ b/Source/Carla/Game/CarlaSettings.h @@ -24,7 +24,7 @@ public: const FWeatherDescription *GetActiveWeatherDescription() const { - if ((WeatherId > 0) && (WeatherId < WeatherDescriptions.Num())) { + if ((WeatherId >= 0) && (WeatherId < WeatherDescriptions.Num())) { return &WeatherDescriptions[WeatherId]; } return nullptr; From d762b249c488a4d3adb0d94b3e2208490efc69b0 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Tue, 23 May 2017 10:45:52 +0100 Subject: [PATCH 11/15] Add begin spawn points for walkers --- Source/Carla/AI/WalkerSpawnPoint.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Source/Carla/AI/WalkerSpawnPoint.h b/Source/Carla/AI/WalkerSpawnPoint.h index d9249df1e..ecf8401df 100644 --- a/Source/Carla/AI/WalkerSpawnPoint.h +++ b/Source/Carla/AI/WalkerSpawnPoint.h @@ -5,9 +5,25 @@ #include "Engine/TargetPoint.h" #include "WalkerSpawnPoint.generated.h" -/// Used to set spawner locations for walkers in the level. -UCLASS() -class CARLA_API AWalkerSpawnPoint : public ATargetPoint +/// Base class for spawner locations for walkers. +UCLASS(Abstract) +class CARLA_API AWalkerSpawnPointBase : public ATargetPoint +{ + GENERATED_BODY() +}; + +/// Used to set spawner locations for walkers in the level. These positions will +/// be used solely to spawn walkers at begin play. +UCLASS() +class CARLA_API AWalkerStartSpawnPoint : public AWalkerSpawnPointBase +{ + GENERATED_BODY() +}; + +/// Used to set spawner locations for walkers in the level. These positions will +/// be used as spawn points as well as destination points for walkers. +UCLASS() +class CARLA_API AWalkerSpawnPoint : public AWalkerSpawnPointBase { GENERATED_BODY() }; From 54cd5fa7751943e332c2344c346c3bb00ec0dea9 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Tue, 23 May 2017 13:44:51 +0100 Subject: [PATCH 12/15] Fix that WITH_EDITOR is also defined when editor is not present --- Source/Carla/Carla.h | 2 +- Source/Carla/CityMapGenerator.cpp | 4 ++-- Source/Carla/MapGen/RoadMap.cpp | 4 ++-- Source/Carla/MapGen/RoadMap.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Source/Carla/Carla.h b/Source/Carla/Carla.h index cd8de7a90..b44bb2e9c 100644 --- a/Source/Carla/Carla.h +++ b/Source/Carla/Carla.h @@ -12,7 +12,7 @@ DECLARE_LOG_CATEGORY_EXTERN(LogCarla, Log, All); DECLARE_LOG_CATEGORY_EXTERN(LogCarlaServer, Log, All); // Options to compile with extra debug options. -#ifdef WITH_EDITOR +#if WITH_EDITOR // #define CARLA_ROAD_GENERATOR_EXTRA_LOG /// @todo #1 Crashes in Linux. // #define CARLA_SERVER_EXTRA_LOG // #define CARLA_TAGGER_EXTRA_LOG diff --git a/Source/Carla/CityMapGenerator.cpp b/Source/Carla/CityMapGenerator.cpp index 743fa3378..a1ac89e94 100644 --- a/Source/Carla/CityMapGenerator.cpp +++ b/Source/Carla/CityMapGenerator.cpp @@ -276,7 +276,7 @@ void ACityMapGenerator::GenerateRoadMap() } } -#ifdef WITH_EDITOR +#if WITH_EDITOR RoadMap->Log(); #endif // WITH_EDITOR @@ -286,7 +286,7 @@ void ACityMapGenerator::GenerateRoadMap() RoadMap->SaveAsPNG(FilePath); } -#ifdef WITH_EDITOR +#if WITH_EDITOR RoadMap->DrawDebugPixelsToLevel(GetWorld(), !bDrawDebugPixelsToLevel); #endif // WITH_EDITOR } diff --git a/Source/Carla/MapGen/RoadMap.cpp b/Source/Carla/MapGen/RoadMap.cpp index 0b96ee84d..a51914e07 100644 --- a/Source/Carla/MapGen/RoadMap.cpp +++ b/Source/Carla/MapGen/RoadMap.cpp @@ -5,7 +5,7 @@ #include "HighResScreenshot.h" -#ifdef WITH_EDITOR +#if WITH_EDITOR #include "DrawDebugHelpers.h" #endif // WITH_EDITOR @@ -261,7 +261,7 @@ bool URoadMap::SaveAsPNG(const FString &Path) const return true; } -#ifdef WITH_EDITOR +#if WITH_EDITOR void URoadMap::Log() const { diff --git a/Source/Carla/MapGen/RoadMap.h b/Source/Carla/MapGen/RoadMap.h index 3ba073526..22a3aca3c 100644 --- a/Source/Carla/MapGen/RoadMap.h +++ b/Source/Carla/MapGen/RoadMap.h @@ -141,7 +141,7 @@ public: /// Save the current map as PNG with the pixel data encoded as color. bool SaveAsPNG(const FString &Path) const; -#ifdef WITH_EDITOR +#if WITH_EDITOR /// Log status of the map to the console. void Log() const; From 795ec2e12eaf8cf907ec5380b8beb8c61174f8f1 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Wed, 24 May 2017 11:31:14 +0100 Subject: [PATCH 13/15] Spawn walkers at begin play and add a black list for misbehaving walkers --- Source/Carla/AI/WalkerSpawnerBase.cpp | 145 +++++++++++++++++------- Source/Carla/AI/WalkerSpawnerBase.h | 17 ++- Source/Carla/Game/CarlaGameModeBase.cpp | 2 +- 3 files changed, 121 insertions(+), 43 deletions(-) diff --git a/Source/Carla/AI/WalkerSpawnerBase.cpp b/Source/Carla/AI/WalkerSpawnerBase.cpp index 813dc8163..94865b24b 100644 --- a/Source/Carla/AI/WalkerSpawnerBase.cpp +++ b/Source/Carla/AI/WalkerSpawnerBase.cpp @@ -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(Walker->GetController()) : nullptr); + return (WalkerIsValid(Walker) ? Cast(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 It(GetWorld()); It; ++It) { - SpawnPoints.Add(*It); + TArray BeginSpawnPoints; + for (TActorIterator It(GetWorld()); It; ++It) { + BeginSpawnPoints.Add(*It); + AWalkerSpawnPoint *SpawnPoint = Cast(*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; } diff --git a/Source/Carla/AI/WalkerSpawnerBase.h b/Source/Carla/AI/WalkerSpawnerBase.h index fd9703e71..f2a186056 100644 --- a/Source/Carla/AI/WalkerSpawnerBase.h +++ b/Source/Carla/AI/WalkerSpawnerBase.h @@ -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 Walkers; + UPROPERTY(Category = "Walker Spawner", VisibleAnywhere, AdvancedDisplay) + TArray WalkersBlackList; + uint32 CurrentIndexToCheck = 0u; }; diff --git a/Source/Carla/Game/CarlaGameModeBase.cpp b/Source/Carla/Game/CarlaGameModeBase.cpp index 19c4c747e..0de5199ca 100644 --- a/Source/Carla/Game/CarlaGameModeBase.cpp +++ b/Source/Carla/Game/CarlaGameModeBase.cpp @@ -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, From 29178cced79330a117c91189658249de6faaffe0 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Wed, 24 May 2017 11:49:14 +0100 Subject: [PATCH 14/15] Count spawned walkers at begin play --- Source/Carla/AI/WalkerSpawnerBase.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/Carla/AI/WalkerSpawnerBase.cpp b/Source/Carla/AI/WalkerSpawnerBase.cpp index 94865b24b..3f12a7fd0 100644 --- a/Source/Carla/AI/WalkerSpawnerBase.cpp +++ b/Source/Carla/AI/WalkerSpawnerBase.cpp @@ -86,9 +86,13 @@ void AWalkerSpawnerBase::BeginPlay() } if (bSpawnWalkers) { + uint32 Count = 0u; for (auto i = 0; i < NumberOfWalkers; ++i) { - TryToSpawnWalkerAt(*BeginSpawnPoints[i % BeginSpawnPoints.Num()]); + if (TryToSpawnWalkerAt(*BeginSpawnPoints[i % BeginSpawnPoints.Num()])) { + ++Count; + } } + UE_LOG(LogCarla, Log, TEXT("Spawned %d walkers at begin play."), Count); } } From dce1075eab333fde4d3e4d1b88cbf5c59d48b2ef Mon Sep 17 00:00:00 2001 From: nsubiron Date: Wed, 24 May 2017 12:32:06 +0100 Subject: [PATCH 15/15] Set new destination to walkers in the black list --- Source/Carla/AI/WalkerSpawnerBase.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Carla/AI/WalkerSpawnerBase.cpp b/Source/Carla/AI/WalkerSpawnerBase.cpp index 3f12a7fd0..7b2b771a2 100644 --- a/Source/Carla/AI/WalkerSpawnerBase.cpp +++ b/Source/Carla/AI/WalkerSpawnerBase.cpp @@ -130,6 +130,7 @@ void AWalkerSpawnerBase::Tick(float DeltaTime) Walker->Destroy(); } } else if (Controller->GetMoveStatus() != EPathFollowingStatus::Moving) { + TrySetDestination(*Walker); WalkersBlackList.Add(Walker); Walkers.RemoveAtSwap(Index); }