C++中调用蓝图资产
UEditorUtilitySubsystem* EditorUtilitySubsystem = GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>(); if (EditorUtilitySubsystem) { FAssetData SuraToolsAsset( TEXT("/SuraControlPanel/SURA-ToolSets511"), // SURA-ToolSets511.uasset TEXT("/SuraControlPanel"), TEXT("SURA-ToolSets511"), UEditorUtilityWidgetBlueprint::StaticClass()->GetClassPathName() ); // asset路径在编辑器里通过Reference Viewer可以获得 auto WidgetBP = CastChecked<UEditorUtilityWidgetBlueprint>(SuraToolsAsset.GetAsset());
if (TabID == NAME_None) { EditorUtilitySubsystem->SpawnAndRegisterTabAndGetID(WidgetBP, TabID); } else { if (EditorUtilitySubsystem->DoesTabExist(TabID)) { EditorUtilitySubsystem->CloseTabByID(TabID); } else { EditorUtilitySubsystem->SpawnRegisteredTabByID(TabID); } } }
FAssetData对象的创建
见#480
FAssetData ShadowCaptureActorAssetData( TEXT("/SURAPlugin/ARShadow/ShadowGenerator/BluePrints/ShadowCapture"), TEXT("/SURAPlugin/ARShadow/ShadowGenerator/BluePrints"), TEXT("ShadowCapture"), TEXT("Blueprint") ); // asset路径在编辑器里通过Reference Viewer可以获得
UE5.1版的新API形式:
// Run test on a single TestPlan asset FName PackageName = FName(FPaths::GetBaseFilename(Path, false)); FName PackagePath = FName(FPaths::GetPath(Path)); FName AssetName = FName(FPaths::GetBaseFilename(Path, true)); FTopLevelAssetPath ClassName = UInterchangeImportTestPlan::StaticClass()->GetClassPathName(); FInterchangeImportTestData& TP = TestPlans.AddDefaulted_GetRef(); TP.AssetData = FAssetData(PackageName, PackagePath, AssetName, ClassName);
UObject类型获取其Asset Path
FTopLevelAssetPath ClassName = UObject::StaticClass()->GetClassPathName(); // // 注意这里UObject类型的AssetPath都是【/Script/Package.Class】的固定格式 // 之所以是这个固定格式,是因为其.generated.h里有DECLARE_CLASS宏调用,其注册的该UObject的PackagePath就是【/Script/Package】的格式 // 例如:/Script/Engine.Blueprint表示Engine模块的UBlueprint // UClass* USuraControlPanelCommonBPLibrary::LoadCppClass( const FString& AssetPath ) { return ::StaticLoadClass(UObject::StaticClass(), nullptr, *AssetPath); }
UObject Paths
Every Asset and Actor that the Unreal Editor has loaded in memory has a path that uniquely identifies it.
In general, these object paths follow the format:
/path/PackageName.ObjectName:SubObjectName.SubObject
Programmers who work with the Engine in C++ may recognize this format as the same one accepted by functions like FindObject() and StaticFindObject().
For example, to deconstruct an Actor path shown in the request examples above:
For example, to deconstruct an Actor path shown in the request examples above:
/Game/ThirdPersonBP/Maps/ | The path to the Asset in the Content Browser. |
ThirdPersonExampleMap.ThirdPersonExampleMap: | The name of the package and the object it contains (for many Assets, these will be the same). |
PersistentLevel.CubeMesh_5.StaticMeshComponent0 | The path through a hierarchy of sub-objects to the object you want to affect. |
Interface在C++中的语法及使用
判断是否实现接口(参考):
- Implements<T>();
- IxxxInterface* TheInterface = Cast<IxxxInterface>(obj);
若是C++里定义的接口,在蓝图里进行了实现,则在C++里通过该对象进行接口调用的方法如下:
auto Owner = GetOwner<APawn>(); if (Owner && Owner->GetClass()->ImplementsInterface(UAnjUpdatePoseInterface::StaticClass())) { IAnjUpdatePoseInterface::Execute_OnPoseUpdate(Owner, PoseData); }
UInterface and IInterface
///////// header file ///////// #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "UObject/Interface.h" #include "WhenCalled.generated.h" class IWhenCalledInterface; class UWhenCalledInterface; UINTERFACE(BlueprintType, MinimalAPI) class UWhenCalledManagerInterface: public UInterface { GENERATED_UINTERFACE_BODY() }; class SURAXR_API IWhenCalledManagerInterface { GENERATED_IINTERFACE_BODY() public: UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR") int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler); virtual void BindDelegates() = 0; }; UINTERFACE(BlueprintType, MinimalAPI) class UWhenCalledInterface: public UInterface { GENERATED_UINTERFACE_BODY() }; class SURAXR_API IWhenCalledInterface { GENERATED_IINTERFACE_BODY() public: UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR") int GetPriority() const; UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR") void DoAtBeginFrame(); UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR") void DoAtEndFrame(); UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR") void DoAtBeginFrameRT(); UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category="SURAXR") void DoAtEndFrameRT(); }; UCLASS(Blueprintable, BlueprintType) class SURAXR_API AWhenCalled : public AActor, public IWhenCalledManagerInterface { GENERATED_BODY() public: // Sets default values for this actor's properties AWhenCalled(); // Begin IWhenCalledManagerInterface // Return: 0 on success; -1 on null Handler; 1 on Handler exists; 2 on Priority conflicts. UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category="SURAXR") int AddHandler(const TScriptInterface<IWhenCalledInterface>& Handler); virtual int AddHandler_Implementation(const TScriptInterface<IWhenCalledInterface>& Handler) override; virtual void BindDelegates() override; // End IWhenCalledManagerInterface protected: // Called when the game starts or when spawned virtual void BeginPlay() override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; public: // Called every frame virtual void Tick(float DeltaTime) override; private: // Begin IWhenCalledManagerInterface UPROPERTY() TMap<int, TScriptInterface<IWhenCalledInterface>> Manager; // End IWhenCalledManagerInterface }; //////// implementation file ////// // Fill out your copyright notice in the Description page of Project Settings. #include "WhenCalled.h" UWhenCalledInterface::UWhenCalledInterface(class FObjectInitializer const &ObjectInitializer) :Super(ObjectInitializer) {} UWhenCalledManagerInterface::UWhenCalledManagerInterface(class FObjectInitializer const &ObjectInitializer) :Super(ObjectInitializer) {} // Sets default values AWhenCalled::AWhenCalled() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; } int AWhenCalled::AddHandler_Implementation( const TScriptInterface<IWhenCalledInterface>& Handler ) { UObject* Object = Handler.GetObject(); IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object); if (Object || IHandler) { if (Manager.FindKey(Handler) != nullptr) { return 1; // Handler exists } TArray<int> Keys; Manager.GetKeys(Keys); for (int k: Keys) { int Prior = IHandler == nullptr? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority(); if (k == Prior) { return 2; // Priority conflicts. } } int Prior = IHandler == nullptr ? IWhenCalledInterface::Execute_GetPriority(Object) : IHandler->GetPriority(); Manager.Add(Prior, Handler); Manager.KeyStableSort([](int A, int B) { return A < B; }); return 0; } return -1; } void AWhenCalled::BindDelegates( ) { FCoreDelegates::OnBeginFrame.AddWeakLambda(this, [this]() { for (auto& iter : Manager) { UObject* Object = iter.Value.GetObject(); if (Object) { IWhenCalledInterface::Execute_DoAtBeginFrame(Object); continue; } IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object); if (IHandler) { IHandler->DoAtBeginFrame(); continue; } } }); FCoreDelegates::OnEndFrame.AddWeakLambda(this, [this]() { for (auto& iter : Manager) { UObject* Object = iter.Value.GetObject(); if (Object) { IWhenCalledInterface::Execute_DoAtEndFrame(Object); continue; } IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(Object); if (IHandler) { IHandler->DoAtEndFrame(); continue; } } }); /*FCoreDelegates::OnBeginFrameRT.AddWeakLambda(this, [this]() { for (auto& iter : Manager) { IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value); if (IHandler) { IHandler->DoAtBeginFrameRT(); } } }); FCoreDelegates::OnEndFrameRT.AddWeakLambda(this, [this]() { for (auto& iter : Manager) { IWhenCalledInterface* IHandler = Cast<IWhenCalledInterface>(iter.Value); if (IHandler) { IHandler->DoAtEndFrameRT(); } } });*/ } // Called when the game starts or when spawned void AWhenCalled::BeginPlay() { Super::BeginPlay(); BindDelegates(); } void AWhenCalled::EndPlay( const EEndPlayReason::Type EndPlayReason ) { Super::EndPlay(EndPlayReason); } // Called every frame void AWhenCalled::Tick(float DeltaTime) { Super::Tick(DeltaTime); }