本記事では、ブループリントノードを右クリックしたときのメニューを追加する方法を説明します。
具体的には、ノード「Sequence」を右クリックしたときに表示されるピン追加/削除のメニューが、ノードを右クリックしたときのメニューの一例です。
なお、基本編の記事 と 実行ピン編の記事 を理解していることを前提に説明します。
- K2Nodeを継承してブループリントノードを自作する(1) 基本編
- K2Nodeを継承してブループリントノードを自作する(2) 実行ピン編
- K2Nodeを継承してブループリントノードを自作する(3) メニュー編 ★本記事
- K2Nodeを継承してブループリントノードを自作する(4) UI編
ソースコード一式
本記事で説明するソースコード一式は、GitHubで公開しています。
https://github.com/colory-games/techblog-sample-projects/tree/main/nutti/20220702
ソースコードを利用して動作確認する場合は、次の手順に従ってください。
- ディレクトリ
MyManualSwitch
を、Unreal EngineのプロジェクトディレクトリにあるPlugins
に配置する .uproject
ファイルを右クリックし、Visual Studio向けのプロジェクトファイルを作成する- プロジェクトファイルを開き、プロジェクトをビルドする
.uproject
ファイルからUnreal Engineを起動し、プラグイン「MyManualSwitch」を有効化する
作成するブループリントノードの仕様
本記事で作成するブループリントノード「MyManualSwitch」の仕様を次に示します。
- 出力側に実行ピン「A」「B」を追加する
- ノードを右クリックしたときにメニューを追加する
- 「Execute A」:実行ピン「A」を実行するように設定する
- 「Execute B」:実行ピン「B」を実行するように設定する
モジュールの作成
基本編で説明した内容に従ってモジュールを作成します。
具体的な作成方法については、基本編の記事 を参考にしてください。
ブループリントノードの作成
ブループリントノードは、次の手順で作成します。
- クラス
UK2Node
の継承 - 基本情報の設定
- ピンの追加
- 実行ピンの処理定義
- メニューを追加
なお、手順1と手順2については 基本編の記事 とほぼ同じであるため、ここでは手順3から説明します。
3. ピンの追加
作成するノードの仕様を満たすように、次のピンを追加します。
ピン名 | 入出力方向 | 意味 |
---|---|---|
入力 | ノードの実行を起動 | |
A | 出力 | 内部ピン「Switch」が True のときにピンの先につながったノードを実行 |
B | 出力 | 内部ピン「Switch」が False のときにピンの先につながったノードを実行 |
Switch | (内部) | True のときに実行ピン「A」の先につながったノードを実行 |
ピンの追加処理は、メンバ関数 AllocateDefaultPins
に実装します。
CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, APinName);
CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, BPinName);
// 内部ピンの作成
UEdGraphPin* SwitchPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Boolean, SwitchPinName);
SwitchPin->DefaultValue = "true";
SwitchPin->bHidden = true;
SwitchPin->bDefaultValueIsReadOnly = true;
SwitchPin->bNotConnectable = true;
入出力側のピンを追加する処理については、基本編の記事 と 実行ピン編の記事 を参考にしてください。
ここでは、実行する実行ピンを切り替えるフラグを保持する内部ピン「Switch」を追加していることに注意します。
内部ピンにするための設定については、基本的に 実行ピン編の記事 と同様です。
ただしメンバ変数 DefaultValue
に値 "true"
を指定することで、ピンのデフォルト値を true
に設定しています。
4. 実行ピンの処理定義
実行ピンの処理を定義します。
今回作成するノード「MyManualSwitch」は、内部ピン「Switch」が True
のときに実行ピン「A」の先につながったノードを実行し、False
のときに実行ピン「B」の先につながったノードを実行します。
この動作を実現するため、実行ピン編の記事 で説明したブループリントのコンパイル処理を定義します。
メンバ関数 Compile
に定義した、ブループリントコンパイル時の処理を示します。
UK2Node_MyManualSwitch* MyManualSwitchNode = CastChecked(Node);
UEdGraphPin* APin = MyManualSwitchNode->FindPin(APinName);
UEdGraphPin* BPin = MyManualSwitchNode->FindPin(BPinName);
// 内部ピン「Switch」の変数を取得する
UEdGraphPin* SwitchPin = MyManualSwitchNode->FindPin(SwitchPinName);
UEdGraphPin* SwitchNet = FEdGraphUtilities::GetNetFromPin(SwitchPin);
FBPTerminal* Switch = Context.NetMap.FindRef(SwitchNet);
// 内部ピン「Switch」の値がFalseのときに、実行ピン「B」に実行制御が移る
FBlueprintCompiledStatement& GotoStatement = Context.AppendStatementForNode(MyManualSwitchNode);
GotoStatement.Type = KCST_GotoIfNot;
GotoStatement.LHS = Switch;
Context.GotoFixupRequestMap.Add(&GotoStatement, BPin);
// 内部ピン「Switch」の値がTrueのときに、実行ピン「A」に実行制御が移る
GenerateSimpleThenGoto(Context, *MyManualSwitchNode, APin);
定義された処理は比較的単純です。
ステートメントタイプ KCST_GotoIfNot
のステートメントを作成し、ステートメント FBlueprintCompiledStatement
の LHS
に内部ピン「Switch」の変数を渡すことで、内部ピン「Switch」の値が False
のときに実行ピン「B」に実行制御が移るという処理を実現します。
実行ピン「A」に実行制御を移す処理は、関数 GenerateSimpleThenGoto
を呼び出して定義します。
5. メニューを追加
ノード「MyManualSwitch」を右クリックしたときに表示されるメニューに対し、項目を追加する方法を説明します。
今回追加するメニューは、内部ピン「Switch」の状態によって異なることに注意が必要です。
- 「Execute A」:実行ピン「A」を実行するように設定する
- 「Execute B」:実行ピン「B」を実行するように設定する
ノードを右クリックしたときに表示されるメニューへ項目を追加するためには、メンバ関数 GetNodeContextMenuActions
をオーバーライドし、項目を追加する処理を定義します。
void UK2Node_MyManualSwitch::GetNodeContextMenuActions(class UToolMenu* Menu, class UGraphNodeContextMenuContext* Context) const
{
Super::GetNodeContextMenuActions(Menu, Context);
FToolMenuSection& Section = Menu->AddSection("K2NodeMyManualSwitch", NSLOCTEXT("K2Node", "MyManualSwitchHeader", "My Manual Switch"));
// 内部ピン「Switch」の値を取得する
UEdGraphPin* Pin = FindPin(SwitchPinName);
bool bExecuteB = Pin->GetDefaultAsString() == "true";
if (!bExecuteB)
{
// メニュー項目「Execute A」を追加する
Section.AddMenuEntry(
"ExecuteA",
LOCTEXT("ExecuteA", "Execute A"),
LOCTEXT("ExecuteATooltip", "Switch to execute A pin"),
FSlateIcon(),
FUIAction(FExecuteAction::CreateUObject(const_cast(this), &UK2Node_MyManualSwitch::ToggleSwitch)));
}
else
{
// メニュー項目「Execute B」を追加する
Section.AddMenuEntry(
"ExecuteB",
LOCTEXT("ExecuteB", "Execute B"),
LOCTEXT("ExecuteBTooltip", "Switch to execute B pin"),
FSlateIcon(),
FUIAction(FExecuteAction::CreateUObject(const_cast(this), &UK2Node_MyManualSwitch::ToggleSwitch)));
}
}
最初に UToolMenu
のメンバ関数 AddSection
を呼び出してメニューのセクション(構造体 FToolMenuSection
)を追加します。
続いて内部ピン「Switch」の値を取得し、構造体 FToolMenuSection
のメンバ関数 AddMenuEntry
を呼び出すことによってメニュー項目を追加します。
内部ピン「Switch」の値によって、追加するメニュー項目を変えている点に注意しましょう。
メンバ関数 AddSection
の第5引数には、内部ピン「Switch」の値を "true"
から "false"
に、もしくは "false"
から "true"
に切り替える処理を定義したメンバ関数 ToggleSwitch
を指定します。
メンバ関数 ToggleSwitch
の定義を次に示します。
void UK2Node_MyManualSwitch::ToggleSwitch()
{
Modify();
// 内部ピン「Switch」の値を変更する
UEdGraphPin* Pin = FindPin(SwitchPinName);
if (Pin->GetDefaultAsString() == "true")
{
Pin->DefaultValue = "false";
}
else
{
Pin->DefaultValue = "true";
}
// ブループリントエディタにデータが変更されたことを通知
FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(GetBlueprint());
}
内部ピン「Switch」の現在の値を確認し、現在の値と反対になるように値を設定しています。
最後に関数 FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified
を呼び出し、ブループリントエディタに対してブループリントアセットが変更されたことを通知します。
この関数を呼び出さないと、ブループリントエディタ上からはブループリントアセットが更新されていない状態としてユーザに見えてしまいます。
具体的にはブループリントアセットが変更された状態であるのに、コンパイルボタンがコンパイル不要のままとなってしまうという現象が発生します。
作成したノードの利用
作成したノードを利用してみましょう。
Actorを作成してブループリントエディタを開き、右クリックでメニューを表示して検索ボックスに「mymaualswitch」を入力します。
カテゴリ「Flow Control」に追加されているノード「MyManualSwitch」を選択して配置します。
作成したActorをレベルに配置して実行すると、現在の内部ピン「Switch」の値によって実行されるピンが変化することが確認できます。
内部ピン「Switch」の値は、ノード「MyManualSwitch」を右クリックしたときに表示されるメニューから変更できます。