Creating SensorSpawnerActor to spawn custom sensors in the editor. (#7149)
* Added spawning sensor logic on begin play in the editor. * Moved spawn sensor logic to SensorSpawnerActor. That can be placed on a level to spawn sensors with custom parameters. * Removing unnecessary logs. * Updating changelog.
This commit is contained in:
parent
7bcbef736b
commit
f6fc4f998d
|
@ -1,6 +1,7 @@
|
|||
## Latest Changes
|
||||
* Prevent from segfault on failing SignalReference identification when loading OpenDrive files
|
||||
* Prevent from segfault on failing SignalReference identification when loading OpenDrive files
|
||||
* Added vehicle doors to the recorder
|
||||
* Creating SensorSpawnerActor to spawn custom sensors in the editor.
|
||||
|
||||
## CARLA 0.9.15
|
||||
|
||||
|
|
|
@ -19,4 +19,4 @@ UCarlaGameInstance::UCarlaGameInstance() {
|
|||
CarlaSettings->LogSettings();
|
||||
}
|
||||
|
||||
UCarlaGameInstance::~UCarlaGameInstance() = default;
|
||||
UCarlaGameInstance::~UCarlaGameInstance() = default;
|
|
@ -130,5 +130,5 @@ private:
|
|||
|
||||
UPROPERTY()
|
||||
FString _MapPath;
|
||||
|
||||
};
|
||||
|
||||
};
|
|
@ -204,6 +204,7 @@ void ACarlaGameModeBase::BeginPlay()
|
|||
|
||||
Episode->InitializeAtBeginPlay();
|
||||
GameInstance->NotifyBeginEpisode(*Episode);
|
||||
OnEpisodeInitialisedDelegate.Broadcast(Episode);
|
||||
|
||||
if (Episode->Weather != nullptr)
|
||||
{
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "CarlaGameModeBase.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnEpisodeInitialisedDelegate, UCarlaEpisode*, InitialisedEpisode);
|
||||
|
||||
/// Base class for the CARLA Game Mode.
|
||||
UCLASS(HideCategories=(ActorTick))
|
||||
class CARLA_API ACarlaGameModeBase : public AGameModeBase
|
||||
|
@ -111,6 +113,8 @@ public:
|
|||
const carla::rpc::MaterialParameter& TextureParam);
|
||||
|
||||
TArray<FString> GetNamesOfAllActors();
|
||||
|
||||
FOnEpisodeInitialisedDelegate OnEpisodeInitialisedDelegate;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
|
||||
#include "Util/SensorSpawnerActor.h"
|
||||
#include "Carla/Game/CarlaEpisode.h"
|
||||
#include "Game/CarlaGameModeBase.h"
|
||||
#include "Sensor/Sensor.h"
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogSensorSpawnerActor, Verbose, All);
|
||||
|
||||
ASensorSpawnerActor::ASensorSpawnerActor()
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
||||
SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComp"));
|
||||
RootComponent = SceneComp;
|
||||
}
|
||||
|
||||
void ASensorSpawnerActor::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
// Wait for the CarlaEpisode initialisation. It is done on CarlaGameMode BeginPlay().
|
||||
if(ACarlaGameModeBase* CarlaGameMode = Cast<ACarlaGameModeBase>(UGameplayStatics::GetGameMode(GetWorld())))
|
||||
{
|
||||
CarlaGameMode->OnEpisodeInitialisedDelegate.AddDynamic(this, &ASensorSpawnerActor::OnEpisodeInitialised);
|
||||
}
|
||||
}
|
||||
|
||||
void ASensorSpawnerActor::OnEpisodeInitialised(UCarlaEpisode* InitialisedEpisode)
|
||||
{
|
||||
if(IsValid(InitialisedEpisode))
|
||||
{
|
||||
CarlaEpisode = InitialisedEpisode;
|
||||
|
||||
// Spawn cameras with initial delay if set.
|
||||
GetWorldTimerManager().SetTimer(InitialDelaySpawnTimerHandle, this, &ASensorSpawnerActor::SpawnSensors, InitialDelay);
|
||||
}
|
||||
}
|
||||
|
||||
void ASensorSpawnerActor::SpawnSensors()
|
||||
{
|
||||
// Check if we are doing a delayed spawn. If so, don't do nothing.
|
||||
if(!SensorsToSpawnCopy.IsEmpty())
|
||||
{
|
||||
UE_LOG(LogSensorSpawnerActor, Warning, TEXT("Warning: ASensorSpawnerActor::SpawnSensors - Delayed spawn already in progress, wait until it ends"));
|
||||
return;
|
||||
}
|
||||
|
||||
if(DelayBetweenSpawns > 0.f)
|
||||
{
|
||||
SensorsToSpawnCopy = SensorsToSpawn;
|
||||
GetWorldTimerManager().SetTimer(SpawnSensorsDelayedTimerHandle, this, &ASensorSpawnerActor::SpawnSensorsDelayed, DelayBetweenSpawns, true);
|
||||
return;
|
||||
}
|
||||
|
||||
for(const auto& SensorStruct : SensorsToSpawn)
|
||||
{
|
||||
if(const FActorDefinition* SensorDefinition = GetActorDefinitionByClass(SensorStruct.SensorClass))
|
||||
{
|
||||
FActorDescription SensorDescription;
|
||||
GenerateSensorActorDescription(SensorDefinition, SensorDescription);
|
||||
|
||||
for(int i = 0; i < SensorStruct.Amount; i++)
|
||||
{
|
||||
SpawnSensorActor(SensorDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const FActorDefinition* ASensorSpawnerActor::GetActorDefinitionByClass(const TSubclassOf<AActor> ActorClass) const
|
||||
{
|
||||
if(!ActorClass || !IsValid(CarlaEpisode))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const TArray<FActorDefinition>& ActorDefinitions = CarlaEpisode->GetActorDefinitions();
|
||||
// Checks that the class is exactly the same. If we want to allow also child classes use: ActorDef.Class->IsChildOf(ActorClass)
|
||||
const FActorDefinition* ActorDefinition = ActorDefinitions.FindByPredicate([&](const FActorDefinition& ActorDef){ return ActorDef.Class == ActorClass; });
|
||||
|
||||
return ActorDefinition;
|
||||
}
|
||||
|
||||
void ASensorSpawnerActor::SpawnSensorActor(const FActorDescription& SensorDescription) const
|
||||
{
|
||||
if(IsValid(CarlaEpisode))
|
||||
{
|
||||
FTransform Transform;
|
||||
GetRandomTransform(Transform);
|
||||
|
||||
CarlaEpisode->SpawnActorWithInfo(Transform, SensorDescription);
|
||||
}
|
||||
}
|
||||
|
||||
void ASensorSpawnerActor::GenerateSensorActorDescription(const FActorDefinition* Definition, FActorDescription& SensorDescription) const
|
||||
{
|
||||
SensorDescription.UId = Definition->UId;
|
||||
SensorDescription.Id = Definition->Id;
|
||||
SensorDescription.Class = Definition->Class;
|
||||
SensorDescription.Variations.Reserve(Definition->Variations.Num());
|
||||
|
||||
FActorAttribute CreatedAttribute;
|
||||
for(const FActorVariation& Variation : Definition->Variations)
|
||||
{
|
||||
if(Variation.RecommendedValues.IsValidIndex(0))
|
||||
{
|
||||
CreatedAttribute.Id = Variation.Id;
|
||||
CreatedAttribute.Type = Variation.Type;
|
||||
CreatedAttribute.Value = Variation.RecommendedValues[0];
|
||||
SensorDescription.Variations.Emplace(CreatedAttribute.Id, CreatedAttribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ASensorSpawnerActor::GetRandomTransform(FTransform &Transform) const
|
||||
{
|
||||
Transform = FTransform::Identity;
|
||||
const float PosX = FMath::FRandRange(MinSpawnLocation.X, MaxSpawnLocation.X);
|
||||
const float PosY = FMath::FRandRange(MinSpawnLocation.Y, MaxSpawnLocation.Y);
|
||||
const float PosZ = FMath::FRandRange(MinSpawnLocation.Z, MaxSpawnLocation.Z);
|
||||
Transform.SetLocation(FVector(PosX, PosY, PosZ));
|
||||
}
|
||||
|
||||
void ASensorSpawnerActor::SpawnSensorsDelayed()
|
||||
{
|
||||
if(SensorsToSpawnCopy.IsEmpty())
|
||||
{
|
||||
GetWorldTimerManager().ClearTimer(SpawnSensorsDelayedTimerHandle);
|
||||
return;
|
||||
}
|
||||
|
||||
if(const FActorDefinition* SensorDefinition = GetActorDefinitionByClass(SensorsToSpawnCopy[0].SensorClass))
|
||||
{
|
||||
FActorDescription SensorDescription;
|
||||
GenerateSensorActorDescription(SensorDefinition, SensorDescription);
|
||||
SpawnSensorActor(SensorDescription);
|
||||
}
|
||||
|
||||
SensorsToSpawnCopy[0].Amount--;
|
||||
|
||||
if(SensorsToSpawnCopy[0].Amount <= 0)
|
||||
{
|
||||
SensorsToSpawnCopy.RemoveAt(0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB). This work is licensed under the terms of the MIT license. For a copy, see <https://opensource.org/licenses/MIT>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "SensorSpawnerActor.generated.h"
|
||||
|
||||
class ASensor;
|
||||
class USceneComponent;
|
||||
class UCarlaEpisode;
|
||||
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FSensorTuple
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
// sensor class to spawn.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
TSubclassOf<ASensor> SensorClass;
|
||||
|
||||
// Number of sensors to spawn of the SensorClass.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
int Amount = 1;
|
||||
};
|
||||
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class CARLA_API ASensorSpawnerActor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
ASensorSpawnerActor();
|
||||
|
||||
// Called OnBeginPlay().
|
||||
UFUNCTION(BlueprintCallable)
|
||||
void SpawnSensors();
|
||||
|
||||
|
||||
protected:
|
||||
// Called when the game starts or when spawned.
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
// Root
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Components")
|
||||
USceneComponent* SceneComp;
|
||||
|
||||
// Array with sensors to spawn
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Config")
|
||||
TArray<FSensorTuple> SensorsToSpawn;
|
||||
|
||||
// Initial delay until the sensors start spawning.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta=(ClampMin=0.f, ClampMax=40.f), Category="Config")
|
||||
float InitialDelay = 6.f;
|
||||
|
||||
// Delay between spawns. Set to 0 for no delay.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, meta=(ClampMin=0.f, ClampMax=40.f), Category="Config")
|
||||
float DelayBetweenSpawns = 0.f;
|
||||
|
||||
// Max spawn location of the sensor. Spawn at random location between MaxSpawnLocation and MinSpawnLocation.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Config")
|
||||
FVector MaxSpawnLocation {-110000.f, -100000.f, 9600.f};
|
||||
|
||||
// Min spawn location of the sensor. Spawn at random location between MaxSpawnLocation and MinSpawnLocation.
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Config")
|
||||
FVector MinSpawnLocation {-120000.f, -110000.f, 9300.f};
|
||||
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void OnEpisodeInitialised(UCarlaEpisode* InitialisedEpisode);
|
||||
|
||||
UFUNCTION()
|
||||
void SpawnSensorsDelayed();
|
||||
|
||||
void GenerateSensorActorDescription(const FActorDefinition* Definition, FActorDescription& SensorDescription) const;
|
||||
|
||||
// Gets a transform with a random location between MaxSpawnLocation and MinSpawnLocation.
|
||||
void GetRandomTransform(FTransform &Transform) const;
|
||||
|
||||
void SpawnSensorActor(const FActorDescription& SensorDescription) const;
|
||||
|
||||
const FActorDefinition* GetActorDefinitionByClass(const TSubclassOf<AActor> ActorClass) const;
|
||||
|
||||
FTimerHandle InitialDelaySpawnTimerHandle;
|
||||
|
||||
UPROPERTY()
|
||||
UCarlaEpisode* CarlaEpisode;
|
||||
|
||||
// Used for delayed spawn
|
||||
FTimerHandle SpawnSensorsDelayedTimerHandle;
|
||||
|
||||
// Used for delayed spawn
|
||||
TArray<FSensorTuple> SensorsToSpawnCopy;
|
||||
};
|
Loading…
Reference in New Issue