I have a number of StaticMeshActors placed inside the World Outliner (the scene) which all use the same static mesh.
I would like to replace all of these with a blueprint that has a static mesh component set as the same static mesh as well. While I replace these I would like to preserve the transform of each selected actor.
Is there an easy way to do this or do I have to do it one by one by instancing the blueprint in the scene and copy/pasting the transforms.
Basically the way I would do this is I would “get all actors of class” (class set to static mesh actor) and then loop through all static meshes to spawn the Blueprint and than destroy the static mesh.
Note that this won’t work in the construction script so I will set it to run on begin play. I’ll show at the end the work around to do it in the editor using Blueprint Utilities.
So first we get all actors of the static mesh class and loop through all of them:
Finally we will spawn the Blueprint you want instead of the static mesh and destroy the static mesh actor after spawning the blueprint (you must spawn the blueprint first otherwise you loose the transform data from the static mesh)
Finally, in order to do this in the editor you will need to use Blueprint Utlities. The construction script does not allow you to spawn actors, unless something has changed recently I’m not aware of.
How ever what we can do is add a custom event in place of the Begin Play event:
You than click on the new custom event and tick on the “Call In Editor” tick box:
Finally, click on the “replace things” blueprint in the level and at the bottom of the details panel you should see a new “Blutilities” option.
Select the “BP Utility” function and select run and it will replace the static meshes with the Blueprint you created:
I was going to attach a screen shot but can’t add any more attachments.
If you don’t see the “Blutilities” just double check you have ticked on the “Call In Editor” option is set on the custom event.
I’ve tried something very similar to your solution. But instead of doing it in Blueprint, I’ve implemented a Blutility class called BP_Utilities in C++ (Which extends from GlobalBlutilityBase). Within the class there is an method called ReplaceSelectedActorsWithBlueprint(). Within it, I get currently selected actors in the world outliner using GEditor->GetSelectedActors() method. Then I replace each of these with an instance of an AActor Class (basically the Blueprint) which is set as an editable global variable in the BP_Utilities class.
There is an issue that the regular GEditor->GetWorld()->SpawnActorFromClass(…) does not work in Blutility scripts, so I haven’t posted my solution yet. If I can fix it by today I will post it. If else I will use your solution.
If you need to only get the “selected” static meshes, once you have them selected just give them a tag (make sure it is under the Actor section and not a component tag).
Just call it something like “TempTag” and than you can modify the Blueprint in the first post to look like this:
I have extended UBlueprintFunctionLibrary in C++ and created a new class called MyUtilityLibrary
The code to replace all the selected objects (currently selected in the World Outliner) is as follows:
void MyUtilityLibrary::ReplaceSelectedActorsWithBlueprint(TSubclassOf<AActor> & blueprintClass)
{
#if WITH_EDITOR
USelection * selection = GEditor->GetSelectedActors();
TArray<AActor*> selectedActors;
selection->GetSelectedObjects<AActor>(selectedActors);
if (!ensureMsgf(selectedActors.Num() > 0, TEXT("Unable to replace selected actors with the given blueprint as no actors are selected."))) {
return;
}
for (auto i = selectedActors.CreateIterator(); i; i++) {
ULevel * actorLevel = (*i)->GetLevel();
FTransform actorTransform = (*i)->GetTransform();
FVector actorScale = (*i)->GetActorScale();
AActor * blueprintActor = GEditor->AddActor(actorLevel, blueprintClass, actorTransform);
blueprintActor->SetActorLabel((*i)->GetActorLabel());
blueprintActor->SetFolderPath((*i)->GetFolderPath());
blueprintActor->SetActorScale3D(actorScale);
(*i)->Destroy();
}
#else
ensureMsgf(false, TEXT("ReplaceSelectedActorsWithBlueprint can only be called in editor builds"));
#endif
}
I’ve also added a Blutility class to set the replacement blueprint as Miroac suggested above. The Blutility class has an event which calls this Library function and passes the blueprint as parameter.
This is the C++ way of doing this in Unreal so its another solution.