I’m not sure if this will help you or not but hopefully it will at least point you in the right direction. First the end results:
This is a class that replicates itself, that is, you add this to your scene and press Play. The class initially will spawn 8 of the same (itself), and instruct the eight to spawn 4 each, then the four to spawn 2, and finally once more for a total of 168 spheres spawned from the main sphere (the sphere you added to the scene manually).
.h
#pragma once
#include "Engine/StaticMeshActor.h"
#include "MyStaticMeshActor.generated.h"
UCLASS()
class YOURPROJECTNAMEHERE_API AMyStaticMeshActor : public AStaticMeshActor
{
GENERATED_BODY()
public:
AMyStaticMeshActor(const FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
virtual void Tick(float DeltaSeconds) override;
protected:
UStaticMesh* SphereMesh;
private:
// first mesh creates 8 8
// second tier creates 4 x 8 32
// forth tier creates 2 x 32 64
// fifth tier creates 1 x 64 64
const int32 DefaultSpawnCount = 8;
const float DefaultSpawnDelta = 3.0f;
bool isDone;
int32 spawnCount;
int32 numberSpawned;
float spawnDelta;
float spawnTime;
};
.cpp
#include "YourProjectNameHere.h"
#include "MyStaticMeshActor.h"
AMyStaticMeshActor::AMyStaticMeshActor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable);
static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereMeshAsset(TEXT("StaticMesh'/Engine/BasicShapes/Sphere.Sphere'"));
SphereMesh = SphereMeshAsset.Object;
PrimaryActorTick.bCanEverTick = true;
isDone = false;
numberSpawned = 0;
spawnCount = DefaultSpawnCount;
spawnDelta = DefaultSpawnDelta;
}
void AMyStaticMeshActor::BeginPlay()
{
Super::BeginPlay();
spawnTime = spawnDelta;
}
void AMyStaticMeshActor::Tick(float DeltaSeconds)
{
const int32 newKEY = -1;
if (numberSpawned < spawnCount)
{
spawnTime -= DeltaSeconds;
if (spawnTime <= 0.0f)
{
spawnTime = spawnDelta;
FVector spawnLocation = FVector(FMath::FRandRange(-500.0f, 500.0f), FMath::FRandRange(-500.0f, 500.0f), FMath::FRandRange(80.0f, 250.0f));
FRotator spawnRotation = FRotator::ZeroRotator;
AMyStaticMeshActor* mesh = GetWorld()->SpawnActor<AMyStaticMeshActor>(this->GetClass(), spawnLocation, spawnRotation);
if (mesh != nullptr)
{
numberSpawned++;
mesh->spawnCount = spawnCount >> 1;
mesh->spawnDelta = FMath::FRandRange(1.5f, 4.5f);
mesh->StaticMeshComponent->SetMobility(EComponentMobility::Movable);
mesh->StaticMeshComponent->SetStaticMesh(SphereMesh);
FString msgText(TEXT("spawnSphere: "));
int32 msgNum = 0;
msgNum++;
GEngine->AddOnScreenDebugMessage(newKEY, 15.0f, FColor::White, msgText + FString("<") + FString::SanitizeFloat(spawnLocation.X)
+ FString(", ") + FString::SanitizeFloat(spawnLocation.Y)
+ FString(", ") + FString::SanitizeFloat(spawnLocation.Z)
+ FString(">"));
}
else
{
FString msgText(TEXT("failed to spawn sphere"));
int32 msgNum = 0;
msgNum++;
GEngine->AddOnScreenDebugMessage(newKEY, 15.0f, FColor::Red, msgText);
}
}
}
else if (!isDone)
{
isDone = true;
FString msgText(TEXT("spawn complete."));
int32 msgNum = 0;
msgNum++;
GEngine->AddOnScreenDebugMessage(newKEY, 15.0f, FColor::Green, msgText);
}
}
There isn’t much error checking going on, and I’m certain better formatting of the spawned location exits, and certainly no optimizations. Notice the SpawnActor<>(this->GetClass(),. . .), and also the SetMobility call. You could create a SphereManager class, move the code to it, and SpawnActor<AMyStaticMeshActor>(AMyStaticMeshActor::StaticClass(),. . .).
Secondly, the SetMobility is probably a gem I’ll need later on. . .but will forget about it. It is my understanding that this call allows you to change material and other properties of static classes.