From f4d55f46445fefceb7281189d4e4c512b3857d15 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 7 Mar 2021 02:34:54 -0500 Subject: [PATCH] Move these from EventCenterPlugin --- .../Private/SpawnableActor.cpp | 92 ++++++++++ .../Private/SpawnableSkeletalMeshActor.cpp | 39 ++++ .../Private/SpawnableStaticMeshActor.cpp | 27 +++ .../Private/SpawningActor.cpp | 171 ++++++++++++++++++ .../Public/SpawnableActor.h | 57 ++++++ .../Public/SpawnableSkeletalMeshActor.h | 38 ++++ .../Public/SpawnableStaticMeshActor.h | 38 ++++ .../Public/SpawningActor.h | 55 ++++++ 8 files changed, 517 insertions(+) create mode 100644 Source/ActorSpawningPlugin/Private/SpawnableActor.cpp create mode 100644 Source/ActorSpawningPlugin/Private/SpawnableSkeletalMeshActor.cpp create mode 100644 Source/ActorSpawningPlugin/Private/SpawnableStaticMeshActor.cpp create mode 100644 Source/ActorSpawningPlugin/Private/SpawningActor.cpp create mode 100644 Source/ActorSpawningPlugin/Public/SpawnableActor.h create mode 100644 Source/ActorSpawningPlugin/Public/SpawnableSkeletalMeshActor.h create mode 100644 Source/ActorSpawningPlugin/Public/SpawnableStaticMeshActor.h create mode 100644 Source/ActorSpawningPlugin/Public/SpawningActor.h diff --git a/Source/ActorSpawningPlugin/Private/SpawnableActor.cpp b/Source/ActorSpawningPlugin/Private/SpawnableActor.cpp new file mode 100644 index 0000000..ca38bd6 --- /dev/null +++ b/Source/ActorSpawningPlugin/Private/SpawnableActor.cpp @@ -0,0 +1,92 @@ +#include "SpawnableActor.h" + +#include "UObject/Object.h" + +DEFINE_LOG_CATEGORY(SpawnableActorLog); + +ASpawnableActor::ASpawnableActor() +{ + UE_LOG(SpawnableActorLog, Log, TEXT("CTOR()")); + + // Set this actor to call Tick() every frame. + // You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + /* + // Attach a mesh to the object. + static ConstructorHelpers::FObjectFinder BaseMeshAsset(TEXT("StaticMesh'/Game/StarterContent/Props/MaterialSphere.MaterialSphere'")); + + BaseMesh = BaseMeshAsset.Object; + + BaseMeshComponent = CreateDefaultSubobject(TEXT("BaseMesh")); + BaseMeshComponent->SetupAttachment(RootComponent); + + BaseMeshComponent->SetStaticMesh(BaseMesh); + + BaseMeshComponent->SetSimulatePhysics(true); + */ + + // NB: Only valid to call in the CTOR. + //BaseMeshComponent = CreateDefaultSubobject(TEXT("BaseMesh")); + //BaseMeshComponent->SetupAttachment(RootComponent); + + // Attach a mesh to the object to try to turn on physics. + // Maybe not necessary... + //static ConstructorHelpers::FObjectFinder BaseMeshAsset(TEXT("StaticMesh'/Game/StarterContent/Props/MaterialSphere.MaterialSphere'")); + //BaseMeshComponent->SetStaticMesh(BaseMeshAsset.Object); + //BaseMeshComponent->SetSimulatePhysics(true); +} + +ASpawnableActor::~ASpawnableActor() +{ +} + +void ASpawnableActor::BeginPlay() +{ + Super::BeginPlay(); +} + +void ASpawnableActor::BeginDestroy() +{ + Super::BeginDestroy(); +} + +void ASpawnableActor::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); +} + +// TODO: This doesn't work outside of constructor +/*void ASpawnableActor::SetMeshByString(const FString& meshName) +{ + // Attach a mesh to the object. + // eg. TEXT("StaticMesh'/Game/StarterContent/Props/MaterialSphere.MaterialSphere'") + static ConstructorHelpers::FObjectFinder BaseMeshAsset(*meshName); + + BaseMesh = BaseMeshAsset.Object; + + BaseMeshComponent = CreateDefaultSubobject(TEXT("BaseMesh")); + + BaseMeshComponent->SetStaticMesh(BaseMesh); + + BaseMeshComponent->SetSimulatePhysics(true); +}*/ + +// Works!! +/*void ASpawnableActor::SetMesh(UStaticMesh* staticMesh) +{ + BaseMesh = staticMesh; + BaseMeshComponent->SetStaticMesh(BaseMesh); + BaseMeshComponent->SetSimulatePhysics(true); + BaseMeshComponent->UpdateCollisionFromStaticMesh(); +}*/ + +void ASpawnableActor::StartDestroyTimer(float seconds) +{ + GetWorldTimerManager().SetTimer(DestroyTimer, this, &ASpawnableActor::InvokeDestroy, seconds); +} + +void ASpawnableActor::InvokeDestroy() +{ + Destroy(); +} diff --git a/Source/ActorSpawningPlugin/Private/SpawnableSkeletalMeshActor.cpp b/Source/ActorSpawningPlugin/Private/SpawnableSkeletalMeshActor.cpp new file mode 100644 index 0000000..5a5c896 --- /dev/null +++ b/Source/ActorSpawningPlugin/Private/SpawnableSkeletalMeshActor.cpp @@ -0,0 +1,39 @@ +#include "SpawnableSkeletalMeshActor.h" + +#include "UObject/Object.h" +#include "Engine/EngineTypes.h" + + +DEFINE_LOG_CATEGORY(SpawnableSkeletalMeshActorLog); + +ASpawnableSkeletalMeshActor::ASpawnableSkeletalMeshActor() +{ + UE_LOG(SpawnableSkeletalMeshActorLog, Log, TEXT("CTOR")); + + // Set this actor to call Tick() every frame. + // You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + BaseMeshComponent = CreateDefaultSubobject(TEXT("BaseMesh")); + RootComponent = BaseMeshComponent; + BaseMeshComponent->SetupAttachment(RootComponent); +} + +ASpawnableSkeletalMeshActor::~ASpawnableSkeletalMeshActor() { +} + +void ASpawnableSkeletalMeshActor::SetSpawnableSkeletalMesh(USkeletalMesh* skeletalMesh) +{ + UE_LOG(SpawnableSkeletalMeshActorLog, Log, TEXT("SetSpawnableSkeletalMesh()")); + + BaseMesh = skeletalMesh; + + BaseMeshComponent->SetSkeletalMesh(BaseMesh); + + BaseMeshComponent->SetCollisionObjectType(ECollisionChannel::ECC_PhysicsBody); + BaseMeshComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); + BaseMeshComponent->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block); + + BaseMeshComponent->SetSimulatePhysics(true); +} + diff --git a/Source/ActorSpawningPlugin/Private/SpawnableStaticMeshActor.cpp b/Source/ActorSpawningPlugin/Private/SpawnableStaticMeshActor.cpp new file mode 100644 index 0000000..231ddda --- /dev/null +++ b/Source/ActorSpawningPlugin/Private/SpawnableStaticMeshActor.cpp @@ -0,0 +1,27 @@ +#include "SpawnableStaticMeshActor.h" + +#include "UObject/Object.h" + +DEFINE_LOG_CATEGORY(SpawnableStaticMeshActorLog); + +ASpawnableStaticMeshActor::ASpawnableStaticMeshActor() +{ + // Set this actor to call Tick() every frame. + // You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; + + BaseMeshComponent = CreateDefaultSubobject(TEXT("BaseMesh")); + BaseMeshComponent->SetupAttachment(RootComponent); +} + +ASpawnableStaticMeshActor::~ASpawnableStaticMeshActor() { +} + +void ASpawnableStaticMeshActor::SetSpawnableStaticMesh(UStaticMesh* staticMesh) +{ + BaseMesh = staticMesh; + BaseMeshComponent->SetStaticMesh(BaseMesh); + BaseMeshComponent->SetSimulatePhysics(true); + BaseMeshComponent->UpdateCollisionFromStaticMesh(); +} + diff --git a/Source/ActorSpawningPlugin/Private/SpawningActor.cpp b/Source/ActorSpawningPlugin/Private/SpawningActor.cpp new file mode 100644 index 0000000..126733d --- /dev/null +++ b/Source/ActorSpawningPlugin/Private/SpawningActor.cpp @@ -0,0 +1,171 @@ +#include "SpawningActor.h" + +#include "SpawnableActor.h" + +#include "Engine/World.h" +#include "UObject/Object.h" +#include "Math/UnrealMathUtility.h" + + +DEFINE_LOG_CATEGORY(SpawningActorLog); + +ASpawningActor::ASpawningActor() +{ + UE_LOG(SpawningActorLog, Log, TEXT("CTOR()")); + + // Set this actor to call Tick() every frame. + // You can turn this off to improve performance if you don't need it. + PrimaryActorTick.bCanEverTick = true; +} + +ASpawningActor::~ASpawningActor() +{ +} + +void ASpawningActor::BeginPlay() +{ + Super::BeginPlay(); +} + +void ASpawningActor::BeginDestroy() +{ + Super::BeginDestroy(); +} + +void ASpawningActor::Tick(float DeltaTime) +{ + Super::Tick(DeltaTime); +} + +ASpawnableActor* ASpawningActor::Spawn() +{ + // Spawn actor + // TODO(bt): This will memory leak. + ASpawnableActor* spawnedActor = (ASpawnableActor*)GetWorld()->SpawnActor(ASpawnableActor::StaticClass()); + + // Get player location + FVector playerLocation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation(); + + + // Teleport actor randomly + // TODO(bt): Put this in front of the camera, or on the (camera -> player) arc! + float x = FMath::RandRange(-4000.0f, 4000.0f); + float y = FMath::RandRange(-4000.0f, 4000.0f); + float z = FMath::RandRange(3000.0f, 10000.0f); + + FVector location( + playerLocation.X + x, + playerLocation.Y + y, + playerLocation.Z + z + ); + + FRotator rotation; + spawnedActor->SetActorLocationAndRotation( + location, + rotation, + false, + 0, + ETeleportType::ResetPhysics + ); + + // We don't want to keep the actor around indefinitely since they may pile up unused. + // Optionally, we could maintain a queue and cull the oldest actors. + spawnedActor->StartDestroyTimer(100.0); + + return spawnedActor; +} + +ASpawnableStaticMeshActor* ASpawningActor::SpawnStaticMeshActor() +{ + // Spawn actor + // TODO(bt): This will memory leak. + ASpawnableStaticMeshActor* spawnedActor = (ASpawnableStaticMeshActor*)GetWorld()->SpawnActor(ASpawnableStaticMeshActor::StaticClass()); + + // Get player location + FVector playerLocation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation(); + + + // Teleport actor randomly + // TODO(bt): Put this in front of the camera, or on the (camera -> player) arc! + float x = FMath::RandRange(-4000.0f, 4000.0f); + float y = FMath::RandRange(-4000.0f, 4000.0f); + float z = FMath::RandRange(3000.0f, 10000.0f); + + FVector location( + playerLocation.X + x, + playerLocation.Y + y, + playerLocation.Z + z + ); + + FRotator rotation; + spawnedActor->SetActorLocationAndRotation( + location, + rotation, + false, + 0, + ETeleportType::ResetPhysics + ); + + // We don't want to keep the actor around indefinitely since they may pile up unused. + // Optionally, we could maintain a queue and cull the oldest actors. + spawnedActor->StartDestroyTimer(100.0); + + return spawnedActor; +} + +ASpawnableSkeletalMeshActor* ASpawningActor::SpawnSkeletalMeshActor() +{ + FActorSpawnParameters actorSpawnParams; + actorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; + + // Spawn actor + // TODO(bt): This will memory leak. + //ASpawnableSkeletalMeshActor* spawnedActor = + // (ASpawnableSkeletalMeshActor*)GetWorld()->SpawnActor(ASpawnableSkeletalMeshActor::StaticClass()); + + // Get player location + FVector playerLocation = GetWorld()->GetFirstPlayerController()->GetPawn()->GetActorLocation(); + + // Teleport actor randomly + // TODO(bt): Put this in front of the camera, or on the (camera -> player) arc! + float x = FMath::RandRange(-4000.0f, 4000.0f); + float y = FMath::RandRange(-4000.0f, 4000.0f); + float z = FMath::RandRange(3000.0f, 10000.0f); + + FVector location( + playerLocation.X + x, + playerLocation.Y + y, + playerLocation.Z + z + ); + + FRotator rotation; + /*spawnedActor->SetActorLocationAndRotation( + location, + rotation, + false, + 0, + ETeleportType::ResetPhysics + );*/ + + ASpawnableSkeletalMeshActor* spawnedActor = + (ASpawnableSkeletalMeshActor*)GetWorld()->SpawnActor( + ASpawnableSkeletalMeshActor::StaticClass(), + &location, + &rotation, + actorSpawnParams + ); + + // We don't want to keep the actor around indefinitely since they may pile up unused. + // Optionally, we could maintain a queue and cull the oldest actors. + spawnedActor->StartDestroyTimer(100.0); + + return spawnedActor; +} + +void ASpawningActor::SpawnCallback(FString Channel, FString Message) +{ + UE_LOG(SpawningActorLog, Log, TEXT("SpawnCallback()")); + + Spawn(); +} + diff --git a/Source/ActorSpawningPlugin/Public/SpawnableActor.h b/Source/ActorSpawningPlugin/Public/SpawnableActor.h new file mode 100644 index 0000000..6cfcf41 --- /dev/null +++ b/Source/ActorSpawningPlugin/Public/SpawnableActor.h @@ -0,0 +1,57 @@ +#pragma once + +// Unreal Core +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "Engine/EngineTypes.h" + +// EventCenterPlugin +#include "SpawnableActor.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(SpawnableActorLog, Log, All); + +// NB(bt): "Blueprintable" seems to remove the ability to add BP event nodes. +UCLASS() +class ACTORSPAWNINGPLUGIN_API ASpawnableActor : public AActor +{ + GENERATED_BODY() + +public: + + ASpawnableActor(); + ~ASpawnableActor(); + + /** Mesh to use */ + //UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpawnableActor", meta = (AllowPrivateAccess = "true")) + //class UStaticMeshComponent* BaseMeshComponent; + + /** Mesh to use */ + //UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpawnableActor", meta = (AllowPrivateAccess = "true")) + //class UStaticMesh* BaseMesh; + + // FIXME: This won't work outside of the ctor :( + //UFUNCTION(BlueprintCallable, Category = "SpawnableActor") + //void SetMeshByString(const FString& meshName); + + //UFUNCTION(BlueprintCallable, Category = "SpawnableActor") + //void SetMesh(UStaticMesh* staticMesh); + + /** Set a timer to destroy this actor. */ + void StartDestroyTimer(float seconds); + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + + virtual void BeginDestroy() override; + + // Destroy timer callback. + void InvokeDestroy(); + + // (Optional) destroy callback timer. + FTimerHandle DestroyTimer; + +public: + // Called every frame + virtual void Tick(float DeltaTime) override; +}; diff --git a/Source/ActorSpawningPlugin/Public/SpawnableSkeletalMeshActor.h b/Source/ActorSpawningPlugin/Public/SpawnableSkeletalMeshActor.h new file mode 100644 index 0000000..77a9d49 --- /dev/null +++ b/Source/ActorSpawningPlugin/Public/SpawnableSkeletalMeshActor.h @@ -0,0 +1,38 @@ +#pragma once + +// Unreal Core +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "Engine/EngineTypes.h" + +// EventCenterPlugin +#include "SpawnableActor.h" +#include "SpawnableSkeletalMeshActor.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(SpawnableSkeletalMeshActorLog, Log, All); + +// NB(bt): "Blueprintable" seems to remove the ability to add BP event nodes. +UCLASS() +class ACTORSPAWNINGPLUGIN_API ASpawnableSkeletalMeshActor : public ASpawnableActor +{ + GENERATED_BODY() + +public: + + ASpawnableSkeletalMeshActor(); + ~ASpawnableSkeletalMeshActor(); + + /** Access to the skeletal mesh component */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpawnableSkeletalMeshActor", meta = (AllowPrivateAccess = "true")) + class USkeletalMeshComponent* BaseMeshComponent; + + /** Set the skeletal mesh. */ + UFUNCTION(BlueprintCallable, Category = "SpawnableSkeletalMeshActor") + void SetSpawnableSkeletalMesh(USkeletalMesh* skeletalMesh); + +private: + /** Mesh to use */ + //UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpawnableActor", meta = (AllowPrivateAccess = "true")) + class USkeletalMesh* BaseMesh; +}; + diff --git a/Source/ActorSpawningPlugin/Public/SpawnableStaticMeshActor.h b/Source/ActorSpawningPlugin/Public/SpawnableStaticMeshActor.h new file mode 100644 index 0000000..9f13f75 --- /dev/null +++ b/Source/ActorSpawningPlugin/Public/SpawnableStaticMeshActor.h @@ -0,0 +1,38 @@ +#pragma once + +// Unreal Core +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "Engine/EngineTypes.h" + +// EventCenterPlugin +#include "SpawnableActor.h" +#include "SpawnableStaticMeshActor.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(SpawnableStaticMeshActorLog, Log, All); + +// NB(bt): "Blueprintable" seems to remove the ability to add BP event nodes. +UCLASS() +class ACTORSPAWNINGPLUGIN_API ASpawnableStaticMeshActor : public ASpawnableActor +{ + GENERATED_BODY() + +public: + + ASpawnableStaticMeshActor(); + ~ASpawnableStaticMeshActor(); + + /** Access to the static mesh component */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpawnableStaticMeshActor", meta = (AllowPrivateAccess = "true")) + class UStaticMeshComponent* BaseMeshComponent; + + /** Set the static mesh. */ + UFUNCTION(BlueprintCallable, Category = "SpawnableStaticMeshActor") + void SetSpawnableStaticMesh(UStaticMesh* staticMesh); + +private: + /** Mesh to use */ + //UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpawnableActor", meta = (AllowPrivateAccess = "true")) + class UStaticMesh* BaseMesh; +}; + diff --git a/Source/ActorSpawningPlugin/Public/SpawningActor.h b/Source/ActorSpawningPlugin/Public/SpawningActor.h new file mode 100644 index 0000000..c7c1f50 --- /dev/null +++ b/Source/ActorSpawningPlugin/Public/SpawningActor.h @@ -0,0 +1,55 @@ +#pragma once + +// Unreal Core +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" + +// EventCenterPlugin +#include "SpawnableActor.h" +#include "SpawnableSkeletalMeshActor.h" +#include "SpawnableStaticMeshActor.h" +#include "SpawningActor.generated.h" + +DECLARE_LOG_CATEGORY_EXTERN(SpawningActorLog, Log, All); + +// NB(bt): "Blueprintable" seems to remove the ability to add BP event nodes. +UCLASS() +class ACTORSPAWNINGPLUGIN_API ASpawningActor : public AActor +{ + GENERATED_BODY() + +public: + + ASpawningActor(); + ~ASpawningActor(); + + /** Create actor. */ + UFUNCTION(BlueprintCallable, Category = "SpawningActor") + ASpawnableActor* Spawn(); + + /** Create actor. */ + UFUNCTION(BlueprintCallable, Category = "SpawningActor") + ASpawnableStaticMeshActor* SpawnStaticMeshActor(); + + /** Create actor. */ + UFUNCTION(BlueprintCallable, Category = "SpawningActor") + ASpawnableSkeletalMeshActor* SpawnSkeletalMeshActor(); + + /** Create actor with delegation callback. */ + UFUNCTION(BlueprintCallable, Category = "SpawningActor") + void SpawnCallback(FString Channel, FString Message); + + /** Mesh to use */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "SpawningActor", meta = (AllowPrivateAccess = "true")) + class UStaticMeshComponent* BaseMesh; + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + + virtual void BeginDestroy() override; + +public: + // Called every frame + virtual void Tick(float DeltaTime) override; +};