Here is how I spawn a blueprint via C++. Note that the blueprint I spawn has a base class that was created in C++ also.
.h
TSubclassOf<YourClass> BlueprintVar; // YourClass is the base class that your blueprint uses
.cpp
ClassThatWillSpawnTheBlueprint::ClassThatWillSpawnTheBlueprint(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
static ConstructorHelpers::FObjectFinder<UBlueprint> PutNameHere(TEXT("Blueprint'/Path/To/Your/Blueprint/BP.BP'"));
if (PutNameHere.Object) {
BlueprintVar = (UClass*)PutNameHere.Object->GeneratedClass;
}
}
PutNameHere
is just an arbitrary name you give to the constructor helper. The path to your blueprint is found by finding your blueprint in the content browser, right clicking it, and choosing Copy Reference
. Then, just paste that in between the quotes.
Now, youāre ready to spawn the blueprint. You can do it in BeginPlay() or wherever, just not in the constructor.
UWorld* const World = GetWorld(); // get a reference to the world
if (World) {
// if world exists
YourClass* YC = World->SpawnActor<YourClass>(BlueprintVar, SpawnLocation, SpawnRotation);
}
If you donāt know your SpawnLocation or SpawnRotation you can just throw in FVector(0,0,0) and FRotator(0,0,0) instead.
So, since your blueprint base class was also created in C++ this makes it easy to interact with your blueprint from code. Itās as simple as YC->SomeVariable = SomeValue
. Hope that helps.
EDIT: A more in depth explanation how this works.
Summary
Communicating with a blueprint via C++ requires some initial setup with the blueprint you need to communicate with. It is not possible to talk to a blueprint variable that was created inside of blueprints via C++. It has to be a C++ variable that the blueprint simply uses. You do this by creating your own base class in C++ for the blueprint, declaring all of the variables that your blueprint will need inside that class, and then setting the parent class of your blueprint to your base C++ class.
Creating the base class
First, you need to create a base class for your blueprint, probably extending from AActor. Then declare your variables in the .h
like so:
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = Projectile)
float ProjectileSpeed; // just an example
Only UPROPERTY
variables will work. BlueprintReadWrite
means this variable can both be read and written to inside of blueprints. EditDefaultsOnly
is optional but it will allow you to edit that variable within the blueprint defaults if you need to. For example, you could tweak the speed without having to recompile everything.
Parenting the blueprint
Once you have your base class written and compiled, you will need to parent your blueprint to that class.
- open blueprint
- click graph
- click blueprint properties
- in the details panel, scroll down until you see Parent Class and use the drop down to choose your C++ class.
You can also set the base class at the time of blueprint creation. As long as your class is compiled it will show up as an option.
Accessing inherited variables inside of blueprints
You will now be able to access the variables you created in your C++ class from inside your blueprint by clicking the āshow inherited variablesā tick box. Since we set the category to āProjectileā above, that is where they will be listed. And since we made them BlueprintReadWrite
, we can use them.
You will have to replace any variables youāve already created in the blueprint with these new inherited variables from the base class. For example if you had created a variable in blueprints called ProjectileSpeed
and used that in 5 different places, you would have to remove all of them, delete that variable and replace them with the inherited ProjectileSpeed
instead. This can get confusing and is a pain, especially if your graph is big. To make this easier you could call the inherited variable something different like ParentProjectileSpeed
or something, that way neither you or the editor will get confused about which is which.
Spawning the blueprint via code and communicating with it
After this is done, you can then spawn and communicate with this blueprint via C++. If your base class is called AMyProjectile
then you would write:
void AClassThatWillSpawnTheBlueprint::BeginPlay()
{
UWorld* const World = GetWorld(); // get a reference to the world
if (World) {
// if world exists
// we are now creating a new instance of this blueprint
AMyProjectile* Missile = World->SpawnActor<AMyProjectile>(BlueprintVar, SpawnLocation, SpawnRotation);
}
// setting a blueprint instance's variable
Missile->ProjectileSpeed = 100;
}
Keep in mind your BlueprintVar
will need to use this base class as well.
TSubclassOf<AMyProjectile> BlueprintVar;