Spawn BP Actor in C++ BlueprintLibrary?

Ok. I’ve been going through tutorials and questions but I must be having a misunderstanding. For a project, one thing I want to try is to create a bunch of random location spheres that fly through the scene and I’m working on practicing the C++/Blueprint integration.

I got a good bit of it working … a C++ actor with an exposed function for movement, a blueprint with a static sphere mesh and a material.

I could place it in the scene manually and trigger it all nicely with blueprints. Cool.

Next I wanted to create a Blueprint Function Library in C++ to manage creating and destroying said spheres and to manage their movement internally.

Made the library, exposed the functions, created a bunch of actors.

But of course they were the actors that the blueprint inherited from, not the blueprint itself, so no sphere mesh, no material, no joy.

I couldn’t figure out how to either spawn the blueprint with the inherited actor or to attach a blueprint/material to the C++ actor, nor do I know the “right” thing I should be doing in UE.

Would love some suggestions / tips. Thanks!

If I am understanding you correctly, (not entirely sure I am though :wink: ), then you can specify a blueprint class derived from your cpp base class with something like this:

	UFUNCTION(BlueprintCallable)
	static AActor* SpawnBall(TSubclassOf<ABallBaseClass> BallClass, UObject *Context);
AActor *UMyBlueprintFunctionLibrary::SpawnBall(TSubclassOf<ABallBaseClass> BallClass, UObject *Context)
{
	return Context->GetWorld()->SpawnActor(BallClass);
}

Appreciate it. Maybe this is along the right direction, but I think I’m also still not quite getting it. It felt like a lot of code to add, but let me add it for clarity :slight_smile: . I’ll skip just the includes for space sake and because there’s nothing special about them.

I have a BallActor.cpp and BallActor.h with a nonsense function defined for now just to make sure it works:

BallActor.h

UCLASS()
class MYPROJECT_API ABallActor : public AStaticMeshActor
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintCallable)
	void doTickMove();
};

BallActor.cpp

void ABallActor::doTickMove() {
	FVector DeltaLocation = FVector(0, -10, 0);
	AddActorWorldOffset(DeltaLocation, false);
}

In the UE5 editor, I created a ball blueprint and a ball material (just an emissive, but my goal is to use custom primitive data for the colors as my next learning attempt!).

The ball blueprint is where I set the parent class as Ball Actor, the static mesh as Sphere, the mobility as Movable, no collision processing, and the material as BallEmissiveMaterial.

Now, wanting to spawn those suckers programmatically, I created a BallBlueprintFunctionLibrary.h and .cpp based on UBlueprintFunctionLibrary:

BallBlueprintFunctionLibrary.h

UCLASS()
class MYPROJECT_API UBallBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
	
public:	
	UFUNCTION(BlueprintCallable)
	static UBallGameInstance* GetBallGameInstanceRef();
	
	UFUNCTION(BlueprintCallable)
	static void BallMover();

	// your new function
	UFUNCTION(BlueprintCallable)
	static AActor* BallSpawn(TSubclassOf<ABallActor> BallClass, UObject* Context);	
};

BallBlueprintFunctionLibrary.cpp

// Including for completeness ... getting the game instance statically and once the world is loaded
UBallGameInstance* UBallBlueprintFunctionLibrary::GetBallGameInstanceRef() {
	static UBallGameInstance* ballGameInstance;
	if (ballGameInstance == NULL) {
		UWorld* world = GEngine->GameViewport->GetWorld();
		if (world)
		{
			UGameInstance* gameInstance = world->GetGameInstance();
			if (gameInstance) {
				ballGameInstance = Cast<UBallGameInstance>(gameInstance);
			}
		}
	}
	if (ballGameInstance)
		return ballGameInstance;
	return NULL;
}

void UBallBlueprintFunctionLibrary::BallMover() {
	static TArray<ABallActor*> BallActors;
	FTransform newBallTransform;
	UBallGameInstance* ballGameInstance = GetBallGameInstanceRef();
	if (!ballGameInstance) {
		return;
	}
	ABallActor* newBall = ballGameInstance->GetWorld()->SpawnActorDeferred<ABallActor>(ABallActor::StaticClass(), newBallTransform);
	if (IsValid(newBall))
	{
		// I have better code to handle the position, but it's longer)
		newBallTransform.TransformPosition(FVector(FMath::RandRange(-100,100),1000, FMath::RandRange(-100,100));
		newBall->FinishSpawning(newBallTransform);
		BallActors.Emplace(newBall);
	}

	// get all actors and move them
	for (ABallActor* actor : BallActors)
	{
		actor->doTickMove();
	}
}

// Your new function
AActor* UBallBlueprintFunctionLibrary::BallSpawn(TSubclassOf<ABallActor> BallClass, UObject* Context) {
	return Context->GetWorld()->SpawnActor(BallClass);
}

Ok. Now I realize this is a silly example, but it should work to make the point.

If I manually drop a BallBlueprint in the scene, the sphere, material, movalbe, and emissive all work. The ball glows and moves towards me and onward. Cool.

If I try to use the code instead to spawn the actors, I can’t figure out how to get the sphere, material, movable / blueprint attached right.

It does successfully spawn something, but of course complains that it’s not movable when the doTickMove is called, and of course it isn’t visible or anything because, no actual mesh.

In UE (I’m trying to learn the preferred way), maybe are we supposed to not create the blueprints for c++ spawnable actors in the UI? Only fully in code? Or is there a way to reference them to attach them to a new actor? Or do we spawn actors with that named blueprint somehow? I’m guessing it’s entirely possible to do it all in code but man, using the UI for simple things like editing defaults of the blueprint or mesh is sure nice and easy.

I just can’t seem to find the “right” answer for something like this where I want to spawn the actors and control them in code.

Thanks!

Hard to tell exactly what is going on here, what is the relation of StartMover() [Declared in header, but implementation not included] and BallMover() [not declared in header, but implementation provided indicating it should be]?

Some observations though:
You are spawning in BallMover, using ABallActor::StaticClass() so only ever going to get the base class. This is what the function taking the TSubClass param is for, so you can specify (in BP) what subclass to spawn.

You should have an object in the world doing this, not a collection of static functions. Storing your actor references in an array the way you are is not going to ‘work’ I am fairly certain (they will get garbage collected if not referenced elsewhere) as they need to be referenced from a UObject UPROP, no statics and certainly no function statics.

Create a Ball Manager (ABallManager) and give it a UPROPERTY() TArray<ABallActor*> Balls, and move your static functions into it (as instance functions, operating on this->Balls).
In the editor, drop one in your level somewhere; you can get a reference (in BP) to it with Find Actor of Class (cache it, if frequently using).
You can then add balls from BP (get the manager, spawn a ball (providing a BP ball subclass)), while adding whatever other C++ functions you need (including overriding Tick()) to operate on them (as the base class though, use virtual functions if you want to do subclass specific things from the generic collection).
The Context that was being passed in before is no longer needed, this object is an actor and becomes the context (something to GetWorld() on), which would be the prefered way to get a world reference, rather than that game instance juggling you are doing (with more statics; they have their place, but you are overdoing it here… get comfortable with instances).

1 Like

Gah, I screwed up my copy/paste. Sorry … in my larger code everything was “star” instead of “ball” (because of the emissive texture). I should have left it alone instead of trying to replace it all for this. I edited the above to hopefully fix that error.

I’ll have to wrap my head around this a bit more. I totally get what you’re saying about reducing the statics (always good, just the only way I could get it working I thought!).

I get the idea of a BallManager class that lives in the world. No problem there and a great way to not have to try to grab the world context other ways.

I get spawning a ball from something happening in the BP world. That worked for me early on. I’ll have to work on the method of spawning from the BallManager? But it sounds more like suggesting adding balls from the BP world, not in C++, so it adds the BP of the final ball? Is that what I’m seeing?

If you want to add BP subclassed balls, then yes that is definitely the suggestion. You are spawning them in CPP, where you can add them to your list for later use (as a pointer to the base class), but that function is called from BP, which passes along the specific BP subclass to spawn.
Getting BP classes from CPP otherwise is not at all straight forward, and interacting with them likewise; If you need to do different things based on the subclass from CPP, then as i said virtual functions are your friend here, but better to avoid that scenario entirely if possible and just put everything you will need from CPP in the CPP base class, and just ‘decorate’ it in the BP subclasses.

1 Like

Thanks for the guidance. I’ll work on it!

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.