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
. 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!