How to execute my custom C++ Actor (procedural level generator) at runtime

Disclaimer: I’m fairly new to UE. I recently moved to it from Unity because of some limitations Unity has (but that’s not the scope of this post).
I translated to C++ a code I wrote in C# (Unity), that generates procedural maps. And now I’m trying to integrate it into UE (after watching/reading lots of tutorials).

What I have done in UE:
I created a new C++ Actor Class that, summarized, does this:

  1. creates an empty Scene Component
  2. sets the Scene Component as RootComponent
  3. using my translated C# code, generates a random bidimensional matrix in memory (the matrix ends up containing different values representing each map piece, 0=empty, 1=floor, 2=wall, etc)
  4. calls a function that reads the matrix, and for each value:
    4.1) creates a new Object corrisponding to the value (using UStaticMeshComponent NewObject())
    4.2) attaches a UStaticMesh to it (using FObjectFinder)
    4.3) attaches it to the Scene RootComponent to use its position as a starting point (using AttachTo(RootComponent))
    4.3) transforms it, accordingly to the matrix indexes, for positioning (using SetRelativeLocation)

Basically everything is inside this Actor’s Constructor (leaving its BeginPlay and Tick blanks). And it works quite well. If I drag and drop the Actor inside the Viewport, it generates a beautiful random dungeon, as expected.

What the problem is:
If I it play, the Actor component gets re-executed, putting new meshes on top of the previous ones, and creating a general mess.

What the question is:
how can I call this actor at runtime (only when I hit play), and, bonus question, how can I move/instantiate a PlayerStart Object to a specific place based on the random generated map?

It’s always difficult to answer these questions without seeing the code but i’ll see what I can do.

What you could try doing is in the GameMode class you can create a virtual function named Begin Play that spawns this particular actor in your world space. GameMode is called before the character being created.

Inside the actual character being created – where he is created doesn’t really matter. Just this->SetActorLocation() as soon as he enters the world.

Since you’re creating a (random landscape right?) what you can do is shoot a Line Trace above the Actor and onto the ground and grab the hit location. Pass this value to the Set Actor Location. If you want a random location shoot multiple lines across a radius, number them(An array), and then randomly select which one you would like.


Part two:

Assuming part 1 didn’t work out… you need to find out what is re-executing in the code. Why is it being called twice? Something tells me that your constructor is the culprit. Unless somewhere in your code you are calling to generate it twice?

In the Generated Mesh’s BeginPlay try putting this in it…

GEngine->AddOnScreenDebugMessage(-1, 5.0, FColor::White, FString::FString(“I am being called!”);

Ideally, this should only appear once. If it does… then it means your generation method needs to be worked on.

ANYWAYS… give these ideas a try and let me know how it goes.

Thank you Master Kyp, BeginPlay inside the GameMode did the trick. This is the code I added inside my TestGameMode.h and TestGameMode.cpp, just for posterity:

//h

public:
virtual void BeginPlay() override;

//cpp

void ATestGameMode::BeginPlay()
{
	Super::BeginPlay();

	UWorld* const World = GetWorld();
	if (World)
	{
		World->SpawnActor<AMapGenerator>(AMapGenerator::StaticClass());
	}    
}

And thanks for the tip on the bonus question too. If I’ll need more help with it I’ll post a specific question. Bye!

I wasn’t able to place the character at runtime so I posted a new question here: :slight_smile: