Skip to the content.

使用C++创建蓝图资源

收到一位朋友公司奇怪的需求,遍历场景内的StaticMeshActor,为每一个都创建一个独立的蓝图资源,并且这个蓝图内包含这个StaticMeshActor.
引用场景并不多,但是我确实不知道如何用代码创建蓝图资源,并且使用代码修改这个蓝图.
通过万能的google我还是查到了关键函数FKismetEditorUtilities::CreateBlueprint
通过阅读这个Kismet函数,发现实际上创建一个蓝图流程非常复杂繁琐,这里就直接使用这个函数创建。

另外CreateBlueprint返回的是一个UBlueprint类型的指针,是没办法想AActor直接attach actor的,依然需要Kismet函数 FKismetEditorUtilities::AddActorsToBlueprint
最后调用FAssetRegistryModule::AssetCreated(newBlueprint);
细节参考以下代码

///这个函数将暴露给蓝图使用 参数将由蓝图传递
void UCreateBPTapPage::CreateLevelBPAssets(TSubclassOf<AActor> ActorTypeParam,const TSoftObjectPtr<UWorld> Level,FString ParentPath, FString BPName)
{
	
///--------------------获取蓝图类和生成的蓝图类---------------------
	UClass* BlueprintClass = nullptr;
	UClass* BlueprintGeneratedClass = nullptr;
	IKismetCompilerInterface& KismetCompilerModule = FModuleManager::LoadModuleChecked<IKismetCompilerInterface>("KismetCompiler");
    
	KismetCompilerModule.GetBlueprintTypesForClass(AActor::StaticClass(), BlueprintClass, BlueprintGeneratedClass);
///---------------------------------------------------------------

///获取关卡资源内包含的Actor 并且判断筛选出特定类型
	for(TActorIterator<AActor> ActorItr(Level->GetWorld());ActorItr;++ActorItr )
	{
		if(ActorItr->IsA(ActorTypeParam))
		{
			FString ActorName = ActorItr->GetName();
			FName BPFName = FName(BPName + ActorName);
			FString PkgPath = FPaths::Combine(ParentPath,  BPFName.ToString());


			UPackage* ParentPackage;
			FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
			FAssetData ExistingAsset = AssetRegistryModule.Get().GetAssetByObjectPath(FName(*PkgPath));

///这里需要判断Asset是否已经存在,经过这一流程虽然在编辑器中已经可以看见,实际上蓝图文件并没有保存在本地磁盘上,所以需要通过AssetRegistryModule判断资源是否已经存在,如果已经存在还试图创建相同名称的UPackage,编辑器将直接闪退。
			if (ExistingAsset.IsValid())
			{
				UE_LOG(LogTemp,Error,TEXT("%s file had exist"),*PkgPath);
				continue;
			}
			
			ParentPackage = CreatePackage(*PkgPath);
			ParentPackage->FullyLoad();
			UBlueprint* newBlueprint = FKismetEditorUtilities::CreateBlueprint(  AActor::StaticClass(), ParentPackage, BPFName, BPTYPE_Normal, BlueprintClass, BlueprintGeneratedClass);
			TArray<AActor*> tempList{*ActorItr};
			FKismetEditorUtilities::FAddActorsToBlueprintParams parms;
			parms.bReplaceActors = false;
			FKismetEditorUtilities::AddActorsToBlueprint(newBlueprint,tempList,parms);
			FAssetRegistryModule::AssetCreated(newBlueprint);
			
		}
	}
}