UnrealEngineでは、ブループリントの変数や関数にアクセスするには、キャストを行う必要があるかと思います。
ブループリント自体が、Classである為、当たり前の事ですが、ブループリントはどちらかというと、
システム的な振る舞いではなく、必要な機能の集合(UnityのPrefabのような扱い方)として、ブループリントを量産したい場合があります。
それらをスポーンする際に、必要なClassをGetAllActorsClass等で探してきてブループリントのキャストをスポーンするというのが、とても面倒だったという事がありました。
上記のノードは、UnrealEngineにおいて、ブループリントからActorをスポーンする事のできる、最も一般的なノードです。
先ほども記載しましたが、このノードでActorをスポーンする為には、GetAllActors系のノードから明確なClassの特定が必要になっています。
例えば、ブループリント名からそのClassの参照の取得やActor化ができないかと考え、調査したメモになります。
#環境
UnrealEngine 4.26.2で検証しています。
また、Runtimeでの動作ではなく、Editor時での動作のみを念頭においています。
#実現方法
実現するにあたって、方法を二通り考えました。
- AssetDataを見つける
- Stringからオブジェクト参照やClass参照を得る
#AssetDataを見つける
この方法は、簡単で分かりやすいですが、負荷もかかり泥臭い方法です。
具体的な方法としては、AssetRegistryのGetAssetsから、名前一致でAssetDataを見つけるという方法です。
例えば、下に載せるようなノードで実現できます。ResultAssetが見つけたClassの参照になります。
AssetDataを取得できている為、そのままActorからスポーンする事も可能です。
注意点として、リストを上から見て、目的のAssetを探すという方法である為、フィルタリングをかけて、検索対象になるClassの数を減らす必要があります。
例として上げたノードでは、「Blueprint」のクラスでフィルタリングしています。
#Stringからオブジェクト参照を得る
続けて、文字列からActorのインスタンス化を行ってみます。
ブループリントのクラス名だと、AssetDataを探す事しか出来ませんが、ObjectPathからオブジェクト参照にキャストする事ができます。
ObjectPathは、フォーマットが決まっている為、生成する事も可能です。
以下のノードを試してみます。
成功しました。
また、キャストをしなくとも、ObjectPathから直接、オブジェクト参照を取得するノードが実装されていました。
こちらのLoadAssetノードでも同じ結果が得られます。
#StringからClass参照を得る
オブジェクト参照でのスポーンが上手くいった為、Classからのスポーンも期待できそうです。
本来、実現したかったのがこちらの方法になります。
オブジェクト参照をキャストした時と同じように、ObjectPathからClass参照をキャストします。
こちらのノードを使う事で、StringからClass参照を取得する事ができます。
ノードを組んでみます。
では、これは上手く行くのか、実行してみます。
何も表示されません。調査してみます。
#StringからClass参照を得る(原因調査)
PrintStringで出したログを見てみます。
すると、以下のエラーが発生しました。
LogStats: FPlatformStackWalk::StackWalkAndDump - 0.624 s
LogOutputDevice: Error: === Handled ensure: ===
LogOutputDevice: Error: Ensure condition failed: !FPackageName::IsShortPackageName(Path) [File:D:/Build/++UE4/Sync/Engine/Source/Runtime/CoreUObject/Private/UObject/SoftObjectPath.cpp] [Line: 79]
LogOutputDevice: Error: Cannot create SoftObjectPath with short package name 'TestClassA'! You must pass in fully qualified package names
LogOutputDevice: Error: Stack:
LogOutputDevice: Error: [Callstack] 0x00007ffe1cca1909 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb78b7c UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1c795810 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1c79554e UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffde2846959 UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffde3500664 UE4Editor-Engine.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb8ae84 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb8d061 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb622fd UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb36b6a UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb61ef1 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb622fd UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb61704 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1c8d2604 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe1cb60e63 UE4Editor-CoreUObject.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe0740208b UE4Editor-UMG.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe07531637 UE4Editor-UMG.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe0749a103 UE4Editor-UMG.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe24b9859e UE4Editor-Slate.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe24bb071e UE4Editor-Slate.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe249f46be UE4Editor-Slate.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe24a77f14 UE4Editor-Slate.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe24a60337 UE4Editor-Slate.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe24a53632 UE4Editor-Slate.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe585dbcb5 UE4Editor-ApplicationCore.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe585c9197 UE4Editor-ApplicationCore.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe585de389 UE4Editor-ApplicationCore.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe585c4310 UE4Editor-ApplicationCore.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe7c33e858 USER32.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe7c33e299 USER32.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe585df914 UE4Editor-ApplicationCore.dll!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff69bc28848 UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff69bc4117c UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff69bc4125a UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff69bc552bd UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ff69bc57fea UE4Editor.exe!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe7af57034 KERNEL32.DLL!UnknownFunction []
LogOutputDevice: Error: [Callstack] 0x00007ffe7cca2651 ntdll.dll!UnknownFunction []
LogStats: SubmitErrorReport - 0.000 s
LogStats: SendNewReport - 12.710 s
LogStats: FDebug::EnsureFailed - 13.341 s
LogScript: Error: D:/Build/++UE4/Sync/Engine/Source/Runtime/Engine/Private/KismetSystemLibrary.cpp(1045): Runtime Error: "MakeSoftClassPathで無効なオブジェクトパス TestClassA。"
LogScript: Error: Script Msg: MakeSoftClassPathで無効なオブジェクトパス TestClassA。
LogScript: Error: Script call stack:
StringToClassTool_C.ExecuteUbergraph_StringToClassTool
StringToClassTool_C.BndEvt__StringToClassTool_Button_0_K2Node_ComponentBoundEvent_0_OnButtonClickedEvent__DelegateSignature
LogUObjectHash: Compacting FUObjectHashTables data took 9.01ms
#何が問題であったか
原因は、以下の部分にあるかと思います。
LogOutputDevice: Error: Cannot create SoftObjectPath with short package name 'TestClassA'! You must pass in fully qualified package names
Class名を渡してみる
LogScript: Error: D:/Build/++UE4/Sync/Engine/Source/Runtime/Engine/Private/KismetSystemLibrary.cpp(1045): Runtime Error: "MakeSoftClassPathで無効なオブジェクトパス TestClassA。"
LogScript: Error: Script Msg: MakeSoftClassPathで無効なオブジェクトパス TestClassA。
LogScript: Error: Script call stack:
StringToClassTool_C.ExecuteUbergraph_StringToClassTool
StringToClassTool_C.BndEvt__StringToClassTool_Button_0_K2Node_ComponentBoundEvent_4_OnButtonClickedEvent__DelegateSignature
LogBlueprintUserMessages: [StringToClassTool_C_1] SoftClassReferenceを存在しない
MakeSoftClassPathでパスが無効という事で、ObjectPathを渡してみる。
LogBlueprintUserMessages: [StringToClassTool_C_4] SoftClassReferenceが存在する
LogBlueprintUserMessages: [StringToClassTool_C_4] ClassReferenceを存在しない
SoftClassReferenceまでは、取得する事ができた。
#LoadBlueprintClassノードとLoadClassAssetBlockingノード
他に方法がないか調べたところ、目的のノードが実装されてました。
「LoadBlueprintClassノード」と「LoadClassAssetBlockingノード」になります。
それぞれ、テスト用のノードを組みテストしてみます。
画像にも記載してある通り、LoadBlueprintClassノードのテストは上手く行きました。
結論
- StringのClass名から直接オブジェクト化やClass参照を取得はできないが、ObjectPathからは可能
- ObjectPathで、オブジェクトを取得したい場合は、LoadAssetを使用する
- ObjectPathで、Class参照を取得したい場合は、LoadBlueprintClassノードを使用する
- ObjectPathも分からず、手掛かりがClass名しか分からない場合は、AssetDataで探す