一般的なブループリントノードのUIはある程度型が決まっており、作成者が意識することなくきれいなUIが表示されます。
しかし一部のブループリントノードは、ユーザがより理解しやすい独自のUIを提供しています。
例えば、ブループリントノード「Switch on Int」はデフォルト実行の上に横棒が追加されているため、条件実行の場合と区別しやすくなっています。
本記事では、メニュー編 で作成したブループリントノードのUIを変更します。
メニュー編の内容を理解する必要はないですが、気になる方は軽く目を通しておきましょう。
- K2Nodeを継承してブループリントノードを自作する(1) 基本編
- K2Nodeを継承してブループリントノードを自作する(2) 実行ピン編
- K2Nodeを継承してブループリントノードを自作する(3) メニュー編
- K2Nodeを継承してブループリントノードを自作する(4) UI編 ★本記事
目次
ソースコード一式
本記事で説明するソースコード一式は、GitHubで公開しています。
https://github.com/colory-games/techblog-sample-projects/tree/main/nutti/20220815
ソースコードを利用して動作確認する場合は、次の手順に従ってください。
- ディレクトリ
MyManualSwitch
を、Unreal EngineのプロジェクトディレクトリにあるPlugins
に配置する .uproject
ファイルを右クリックし、Visual Studio向けのプロジェクトファイルを作成する- プロジェクトファイルを開き、プロジェクトをビルドする
.uproject
ファイルからUnreal Engineを起動し、プラグイン「MyManualSwitch」を有効化する
変更前後のUI
ブループリントノード「MyManualSwitch」について、変更後のUIを示します。
入力側の実行ピンの下に、横棒と実行先を表すテキストが新たに追加されていることが分かります。
実行先を表すテキストは、実行先の変更にあわせて変化することにも注目しましょう。
モジュールの作成
基本編で説明した内容に従ってモジュールを作成します。
具体的な作成方法については、基本編の記事 を参考にしてください。
ブループリントノードのUI変更手順
ブループリントノードのUIは、次の手順で変更します。
- クラス
SGraphNodeK2Base
の継承 - 基本情報の設定
- UI構築処理の定義
- UIとブループリントノードの関連づけ
1. クラス SGraphNodeK2Base
の継承
最初にクラス SGraphNodeK2Base
を継承したクラス SGraphNodeMyManualSwitch
を定義します。
class SGraphNodeMyManualSwitch : public SGraphNodeK2Base
{
SLATE_BEGIN_ARGS(SGraphNodeMyManualSwitch)
{
}
SLATE_END_ARGS()
void Construct(const FArguments& InArgs, UK2Node_MyManualSwitch* InNode);
virtual void CreatePinWidgets() override;
};
マクロ SLATE_BEGIN_ARGS
と SLATE_END_ARGS
は、インスタンス化するときに渡すことができるパラメータの仕様を定義するものですが、今回の場合は使用しません。
クラス SGraphNodeMyManualSwitch
には、2つのメンバ関数があります。
メンバ関数名 | 意味 |
---|---|
Construct |
インスタンス化時に呼ばれる。 基本情報をここで設定する。 |
CreatePinWidgets |
入出力のピンを描画するときに呼ばれる。 UI構築処理をここで定義する。 |
2. 基本情報の設定
基本情報の設定は、クラス SGraphNodeMyManualSwitch
のメンバ関数 Construct
に設定の処理を定義することで行えます。
void SGraphNodeMyManualSwitch::Construct(const FArguments& InArgs, UK2Node_MyManualSwitch* InNode)
{
GraphNode = InNode;
SetCursor(EMouseCursor::GrabHand);
UpdateGraphNode();
}
GraphNode
は親クラスに定義されているメンバ変数で、のちほどUIを構築する処理を定義するために利用します。
ここでは、引数の InNode
をそのまま代入するのが一般的です。
次にメンバ関数 SetCursor
を呼び出し、ブループリントノード上にマウスオーバーしたときにカーソルが手のアイコンに変更されるようにします。
メンバ関数 SetCursor
に渡せる列挙型 EMouseCursor
の値によって、表示するカーソルのアイコンを変更できる点に注意しましょう。
最後にメンバ関数 UpdateGraphNode
を呼び出し、ブループリントノードのUIに変更があったことを通知します。
3. UI構築処理の定義
クラス SGraphNode
のメンバ関数 CreatePinWidgets
をオーバーライドしてUIを構築する処理を定義します。
UIの構築は、Unreal Engineの スレートUIフレームワーク にしたがって構築します。
void SGraphNodeMyManualSwitch::CreatePinWidgets()
{
UK2Node_MyManualSwitch* MyManualSwitch = CastChecked(GraphNode);
// ピンのUIを追加
for (auto It = GraphNode->Pins.CreateConstIterator(); It; ++It)
{
UEdGraphPin* Pin = *It;
if (!Pin->bHidden)
{
TSharedPtr NewPin = FNodeFactory::CreatePinWidget(Pin);
check(NewPin.IsValid());
AddPin(NewPin.ToSharedRef());
}
}
bool bExecuteA = MyManualSwitch->GetSwitchValue();
// 横棒を追加
LeftNodeBox->AddSlot()
.AutoHeight()
.HAlign(HAlign_Left)
.VAlign(VAlign_Center)
[
SNew(SImage)
.Image(FEditorStyle::GetBrush("Graph.Pin.DefaultPinSeparator"))
];
// 実行先のテキストを追加
LeftNodeBox->AddSlot()
.AutoHeight()
.HAlign(HAlign_Left)
.VAlign(VAlign_Center)
.Padding(10.0f, 5.0f)
[
SNew(STextBlock)
.Text(FText::FromString(bExecuteA ? "Execute A" : "Execute B"))
];
}
スレートUIフレームワークについてはここでは詳しく説明しませんが、ブループリントノードのUIを構築する処理で2つ補足します。
ピンの追加
クラス FNodeFactory
のメンバ関数 CreatePinWidget
で作成し、メンバ関数 AddPin
を呼び出すことでブループリントノードのUIに追加できます。
独自にピンのUIを作ることもできますが、デフォルトのUIを利用するのであればこれらのメンバ関数を利用するのが手っ取り早く実装できるでしょう。
ピンには入出力の方向があるため追加するUIの場所がそれぞれ異なりますが、メンバ関数 AddPin
はピンの入出力によって追加するUIの場所を自動的に判断してくれます。
LeftNodeBox
今回はブループリントノードの左側にUIを追加するため、メンバ変数 LeftNodeBox
に対して横棒と実行先のテキストを追加しています。
ブループリントノードの右側にUIを追加する場合は、メンバ変数 RightNodeBox
に対して操作を行います。
このようにブループリントノードに対してUIを変更する場合は、LeftNodeBox
もしくは RightNodeBox
に対して操作を行うことになります。
4. UIとブループリントノードの関連づけ
最後にクラス SGraphNodeK2Base
で定義したUIとブループリントノード(クラス UK2Node_MyManualSwitch
)を関連づけます。
モジュールロード時に実行されるメンバ関数 FMyManualSwitchModule::StartupModule
に該当の処理を追加することで関連づけが可能です。
void FMyManualSwitchModule::StartupModule()
{
GraphPanelNodeFactory_MyManualSwitch = MakeShareable(new FGraphPanelNodeFactory_MyManualSwitch());
FEdGraphUtilities::RegisterVisualNodeFactory(GraphPanelNodeFactory_MyManualSwitch);
}
今回はクラス FGraphPanelNodeFactory_MyManualSwitch
を定義し、そのインスタンスをメンバ関数 FEdGraphUtilities::RegisterVisualNodeFactory
に渡すことで実現しています。
クラス FGraphPanelNodeFactory_MyManualSwitch
の定義を次に示します。
class FGraphPanelNodeFactory_MyManualSwitch : public FGraphPanelNodeFactory
{
virtual TSharedPtr CreateNode(UEdGraphNode* Node) const override
{
if (UK2Node_MyManualSwitch* MyManualSwitch = Cast(Node))
{
return SNew(SGraphNodeMyManualSwitch, MyManualSwitch);
}
return nullptr;
}
};
クラス FGraphPanelNodeFactory
を継承し、メンバ関数 CreateNode
をオーバーライドします。
メンバ関数 CreateNode
の引数にはクラス UEdGraphNode
から継承されたブループリントノードが渡されてくるため、そのブループリントノードが UK2Node_MyManualSwitch
であるか否かを判定します。
UK2Node_MyManualSwitch
の場合は、SNew
を呼び出して SGraphNodeMyManualSwitch
をインスタンス化して返します。
これによって、ユーザが UK2Node_MyManualSwitch
を追加した時に SGraphNodeMyManualSwitch
が呼ばれて専用のUIが表示されるようになります。
関連づけたUIは、モジュールアンロード時に関連づけを解除する必要があります。
void FMyManualSwitchModule::ShutdownModule()
{
if (GraphPanelNodeFactory_MyManualSwitch.IsValid())
{
FEdGraphUtilities::UnregisterVisualNodeFactory(GraphPanelNodeFactory_MyManualSwitch);
GraphPanelNodeFactory_MyManualSwitch.Reset();
}
}
作成したノードの利用
作成したノードを利用してみましょう。
Actorを作成してブループリントエディタを開き、右クリックでメニューを表示して検索ボックスに「mymaualswitch」を入力します。
カテゴリ「Flow Control」に追加されているノード「MyManualSwitch」を選択して配置します。
この状態でブループリントノードを右クリックして実行先を変更すると、現在の実行先に応じて表示されるテキストが変化します。