はじめに
先日から続いてる Chooser 関連の記事シリーズ 第3弾!
pafuhana1213.hatenablog.com
pafuhana1213.hatenablog.com
Chooserの設定方法やBPで使う方法については書きましたが、実際にプロジェクトで使い祭は C++ で Chooser Table, Proxy Tableを使う方法を知りたいところですよね!
早速ググってみると…出てこないいいいいいい!
なんだ、この記事たちは!参考にならん!!!

ということで、世の中に情報がなかったのでエンジンコードを頼りに「Evaluate Chooser / Proxy を C++から呼ぶ方法について調べてみました…!
Evaluate Chooser を C++ で実行する方法
色々調べたところ、C++ で Chooser を使う際はUChooserFunctionLibrary
で用意された各関数を使うのが良さそうです!
UChooserFunctionLibrary
EvaluateChooser
最もシンプル。ContextObject
にはChooserTable
の入出力パラメータにおけるUObject
を渡し、ObjectClass
にはChooserTable
のResultClass
を設定
UFUNCTION(BlueprintPure, meta = (BlueprintThreadSafe, BlueprintInternalUseOnly = "true", DeterminesOutputType = "ObjectClass"))
static UObject* EvaluateChooser(const UObject* ContextObject, const UChooserTable* ChooserTable, TSubclassOf<UObject> ObjectClass);
EvaluateChooserMulti
EvaluateChooser
の複数結果を返す版
UFUNCTION(BlueprintPure, meta = (BlueprintThreadSafe, BlueprintInternalUseOnly = "true", DeterminesOutputType = "ObjectClass"))
static TArray<UObject*> EvaluateChooserMulti(const UObject* ContextObject, const UChooserTable* ChooserTable, TSubclassOf<UObject> ObjectClass);
EvaluateObjectChooserBase
UObject
ではなく、Chooser専用のFChooserEvaluationContext
を渡す関数
FChooserEvaluationContext
にはChooserTable
の入出力パラメータを複数設定することが可能(後述)
UFUNCTION(BlueprintCallable, meta = (BlueprintThreadSafe, BlueprintInternalUseOnly = "true", DeterminesOutputType = "ObjectClass"))
static UObject* EvaluateObjectChooserBase(UPARAM(Ref) FChooserEvaluationContext& Context,UPARAM(Ref) const FInstancedStruct& ObjectChooser, TSubclassOf<UObject> ObjectClass, bool bResultIsClass = false);
EvaluateObjectChooserBaseMulti
EvaluateObjectChooserBase
の複数結果を返す版
UFUNCTION(BlueprintCallable, meta = (BlueprintThreadSafe, BlueprintInternalUseOnly = "true", DeterminesOutputType = "ObjectClass"))
static TArray<UObject*> EvaluateObjectChooserBaseMulti(UPARAM(Ref) FChooserEvaluationContext& Context,UPARAM(Ref) const FInstancedStruct& ObjectChooser, TSubclassOf<UObject> ObjectClass, bool bResultIsClass = false);
FChooserEvaluationContext
に 入出力パラメータである UObject
を設定する関数。C++のみで完結する場合は FChooserEvaluationContext
のAddObjectParam
関数を使ったほうがシンプル
UFUNCTION(BlueprintCallable, meta = (BlueprintThreadSafe, BlueprintInternalUseOnly = "true"))
static void AddChooserObjectInput(UPARAM(Ref) FChooserEvaluationContext& Context, UObject* Object);
FChooserEvaluationContext
に 入出力パラメータである Struct
を設定する関数。ただC++のみで完結する場合は FChooserEvaluationContext
のAddStructParam
関数を使ったほうがシンプル。
UFUNCTION(BlueprintCallable, CustomThunk, meta = (BlueprintThreadSafe, BlueprintInternalUseOnly = "true", CustomStructureParam = "Value"))
static void AddChooserStructInput(UPARAM(Ref) FChooserEvaluationContext& Context, int32 Value);
DECLARE_FUNCTION(execAddChooserStructInput);
GetChooserStructOutput
FChooserEvaluationContext
に 入出力パラメータである Struct
を取得する関数。ただこれはEvaluate Chooser
ノードが動的にピンを生成するのに使われているものであり、C++のみで完結する場合はあまり使用する機会はないかも
UFUNCTION(BlueprintPure, CustomThunk, meta = (BlueprintThreadSafe, BlueprintInternalUseOnly = "true", CustomStructureParam = "Value"))
static void GetChooserStructOutput(UPARAM(Ref) FChooserEvaluationContext& Context, int Index, int32& Value);
DECLARE_FUNCTION(execGetChooserStructOutput);
MakeEvaluateChooser
ChooserTable
からInstancedStruct(/Script/Chooser.ObjectChooserBase
)を生成する関数。EvaluateObjectChooserBase(Multi)
を使う際はこのInstancedStructが必要になる
UFUNCTION(BlueprintPure, Category = "Animation", meta = (BlueprintThreadSafe, BlueprintInternalUseOnly="true", NativeMakeFunc))
static FInstancedStruct MakeEvaluateChooser(UChooserTable* Chooser);
MakeChooserEvaluationContext
空のFChooserEvaluationContext
を作成する関数。ただ FChooserEvaluationContext Context;
で十分(内部実装もそうだし)
UFUNCTION(BlueprintCallable, Category = "Animation", meta = (BlueprintThreadSafe, BlueprintInternalUseOnly="true"))
static FChooserEvaluationContext MakeChooserEvaluationContext();
サンプルコード
で、これらを使うことでEvaluateChooserと同様に、ChooserTableを使った選定処理を独自のC++コードで実装することができます!
UFUNCTION(BlueprintCallable)
UObject* GetObjectFromChooserTable( UChooserTable* ChooserTable, const TSubclassOf<UObject> ObjectClass,
UPARAM(Ref) FXXXInput& Input,FXXXOutput& Output);
UObject* AXXX::GetObjectFromChooserTable(UChooserTable* ChooserTable, const TSubclassOf<UObject> ObjectClass,
FXXXInput& Input,FXXXOutput& Output)
{
if(ChooserTable)
{
FChooserEvaluationContext Context;
Context.AddObjectParam(this);
Context.AddStructParam(Input);
Context.AddStructParam(Output);
FInstancedStruct ChooserStruct = UChooserFunctionLibrary::MakeEvaluateChooser(ChooserTable);
return UChooserFunctionLibrary::EvaluateObjectChooserBase(
Context, ChooserStruct, ObjectClass, false);
}
return nullptr;
}

(表示するStaticMeshアセットをパラメータに応じて変化、というもの)
EvaluateChooser
ノードと違い「基底クラスで処理を書き、派生クラスで使用するChooserTableを設定する」ことができるため、前回の記事にて書いた欠点を解決することができます!
ただChooserTableのResult Class・入出力パラメータの変化には弱く、クラス設定やパラメータの数が変化すると問題が起きることが EvaluateChooser
ノードに比べると多そうです。
ちなみに、Chooserに関する処理は各クラスがオススメです!
FAnimNode_ChooserPlayer
(Chooser Playerノード)
UK2Node_EvaluateChooser2
( Evaluate Chooserノード)
- 動的にピンを生成したりしてるので少し複雑
UK2Node_EvaluateChooser
というのもありますが、こちらは古いコードの模様
ちなみに、↑のChooser Player
ノードはこちら。ABP(AnimInstance)を内部で渡してくれるので、Animation Chooser設定で作ったChooser TableをAnimGraph 内で使う際に便利です!

Evaluate Proxyを C++ で実行する方法
こちらは UProxyTableFunctionLibrary
を使うのがオススメです。ただProxyAssetがまだExperimentalであったり、一時的な後方互換のために用意された関数があったりします。
そのため、実際に使うのはMakeLookupProxyWithOverrideTable
だけです。
UProxyTableFunctionLibrary
MakeLookupProxyWithOverrideTable
ProxyTableの処理で使う InstnacedStruct(FLookupProxyWithOverrideTable
)を生成する関数。
UFUNCTION(BlueprintPure, Category = "Animation", meta = (BlueprintThreadSafe, BlueprintInternalUseOnly="true"))
static FInstancedStruct MakeLookupProxyWithOverrideTable(UProxyAsset* Proxy, UProxyTable* ProxyTable);
FInstancedStruct UProxyTableFunctionLibrary::MakeLookupProxyWithOverrideTable(UProxyAsset* Proxy, UProxyTable* ProxyTable)
{
FInstancedStruct Struct;
Struct.InitializeAs(FLookupProxyWithOverrideTable::StaticStruct());
FLookupProxyWithOverrideTable& Data = Struct.GetMutable<FLookupProxyWithOverrideTable>();
Data.Proxy = Proxy;
Data.OverrideProxyTable = ProxyTable;
return Struct;
}
サンプルコード
で、これを使うことでEvaluateProxy
と同様に、ProxyAsset
, ProxyTable
を使った選定処理を独自のC++コードで実装することができます!
UObject* AXXX::GetObjectFromProxyTable(UProxyTable* ProxyTable, UProxyAsset* ProxyAsset)
{
if(ProxyTable && ProxyAsset)
{
FInstancedStruct ProxyStruct =
UProxyTableFunctionLibrary::MakeLookupProxyWithOverrideTable(ProxyAsset, ProxyTable);
FLookupProxyWithOverrideTable& LookupProxy = ProxyStruct.GetMutable<FLookupProxyWithOverrideTable>();
FChooserEvaluationContext Context;
return LookupProxy.ChooseObject(Context);
}
return nullptr;
}

ProxyTable
はChooserTable
と比べると設定パラメータが少ないので、C++で実装する際もシンプル!(その分できることも少ないですが…)
前回の記事にも書いた通り、ChooserTableの長所である条件判定処理が不要で、ID(ProxyAsset)が確定している場合は今回のようなコードでプロジェクト独自のアセット管理・取得処理を書いておくと便利だと思います。
さいごに
ChooserをC++で扱うには色々複雑になるのかなぁ…と思っていたら、案外シンプルに実装できることがわかって一安心です!
Chooserは多機能で便利ではありますが、その反面プロジェクトにおける運用・管理フローを整備しないとカオスなことになりそうです。そして、Evaluate Chooser / Proxyでは物足りない部分をC++で独自実装しておくとフローがスッキリしたり、設定ミスなどによるヒューマンエラーも防げる気がしました!
そんなこんなで少しでも参考になれば幸いです。(次はChooserTableアセットの自動生成・設定を調べていきたいところ)
おしまい