Visual Script Graph ノードの作成
Visual Scripting でのプログラミングは、ロジックのブロックを接続することで行われます。このブロックはノードと呼ばれます。
Visual Scripting には、異なるアクションに特化した様々なノードタイプがあります。
- Events: アクション実行の入口です。例えば OnStart、OnUpdate、OnButton などです。
- Flow: 実行されるために別のノードによってトリガーされる必要があるノードです。例えば if Position や set Position です。
- Data: 浮動小数点数リテラル (float literal) や整数リテラル (integer literal) などのデータを含んだノードです。
単純なカスタムノードの作成
以下の手順で、空ノードを新規作成できます。
プロジェクト内を右クリックし、Create > C# Script を選択して、ノードの名前を持つ C# ファイルをプロジェクト内に作成します。
例: MyNode.cs以下のコードをコピーして、スクリプト内に貼り付けて保存します。
using Unity.VisualScripting; public class MyNode : Unit { protected override void Definition() //The method to set what our node will be doing. { } }
Edit > Project Settings を選択してください。 Project Settings ウィンドウが表示されます。
Project Settings ウィンドウで Visual Scripting を選択し、Regenerate Nodes を選択してファジーファインダーに新しいノードを追加します。
新しいノードをグラフ内に追加するには、任意の Script Graph の背景を右クリックしてください。ファジーファインダーの末尾に新しいノードが表示されます。
ファジーファインダーで新しいノードを選択してください。グラフ内に My Node ノードが表示されます。

Note
Visual Scripting はカスタムノードを自動的に処理します。Node Library のリストに C# ファイルを追加する必要はありません。
ポートの追加とコードの実行
ノードを作成する時は、ポートを追加する必要があります。その理由は以下の通りです。
- 解釈されるデータをユーザーが追加できるようにするため。
- 制御ポートを設定して、現在のノードアクションの完了後にユーザーがそのノードと他のノードの両方をトリガーできるようにするため。
これを行うために、4 つの異なるタイプのポートをノード上に作成できます。
ポート:
- ControlInput: ロジックとノードを実行する入口です。
- ControlOutput: そのポートに接続された次のアクションをトリガーします。
- ValueInput: ノードに渡したい各種のデータです。
- ValueOutput: ノードの外で渡したい各種のデータです。
制御ポートの追加
ポートをノードに表示させるには、以下を行ってください。
- ControlInput タイプと ControlOutput タイプの任意のポート変数を追加します。
- Definition メソッドでそのポート変数を使用します。
using Unity.VisualScripting;
public class MyNode : Unit
{
[DoNotSerialize] // ポートをシリアル化する必要はありません。
public ControlInput inputTrigger; //ControlInput ポート変数を追加します。
[DoNotSerialize] // ポートをシリアル化する必要はありません。
public ControlOutput outputTrigger;//ControlOutput ポート変数を追加します。
protected override void Definition()
{
//outputTrigger ポートにフローを渡すために、ControlInput ポートを表示し、そのキーを設定し、匿名アクションメソッドを実行します。
inputTrigger = ControlInput("inputTrigger", (flow) => { return outputTrigger; });
//ControlOutput ポートを表示し、そのキーを設定しています。
outputTrigger = ControlOutput("outputTrigger");
}
}
これで、他の制御ポートに接続できる状態の、機能する基本的な Flow Routing ノードが作成されました。Flow Routing ノードを使用すれば、管理の難しい非構造化ビジュアルソースコードを回避するために、グラフ内のフローの方向を変えることができます。
値ポートの追加
値ポートを追加するには、ノードに入力したいデータの型を定義する必要があります。データには以下の 2 つの型があります。
- Generic: 様々な型を入力してノードに扱わせたい形でデータを扱わせるために使用できるオブジェクトタイプです。
- Type Value: 文字列 (string)、整数 (integer)、浮動小数点数 (float) など、特定のデータ型を強制するために使用されます。
以下のサンプルコードは、2 つの string 型の入力値と 1 つの string 型の出力値を追加します。デフォルト値を追加することも可能です。以下のサンプルコード内では、myValueA のデフォルトの string 値が “Hello” に設定されています。
using Unity.VisualScripting;
public class MyNode : Unit
{
[DoNotSerialize]
public ControlInput inputTrigger;
[DoNotSerialize]
public ControlOutput outputTrigger;
[DoNotSerialize] // ポートをシリアル化する必要はありません。
public ValueInput myValueA; // myValueA の ValueInput 変数を追加します。
[DoNotSerialize] // ポートをシリアル化する必要はありません。
public ValueInput myValueB; // myValueB の ValueInput 変数を追加します。
[DoNotSerialize] // ポートをシリアル化する必要はありません。
public ValueOutput result; // 結果の ValueOutput 変数を追加します。
private string resultValue; // 処理された結果の値の string 変数を追加します。
protected override void Definition()
{
inputTrigger = ControlInput("inputTrigger", (flow) => { return outputTrigger; });
outputTrigger = ControlOutput("outputTrigger");
//myValueA 入力値ポートを表示し、ポートのラベル名を myValueA に設定し、そのデフォルト値を Hello に設定します。
myValueA = ValueInput<string>("myValueA", "Hello ");
//myValueB 入力値ポートを表示し、ポートのラベル名を myValueB に設定し、そのデフォルト値を空の文字列に設定します。
myValueB = ValueInput<string>("myValueB", string.Empty);
//結果の出力値ポートを表示し、ポートのラベル名を result に設定し、そのデフォルト値を resultValue 変数に設定します。
result = ValueOutput<string>("result", (flow) => { return resultValue; });
}
}
現在のノードを接続しようとすると、フローはそれを通過しますが、Result 値は null になります。resultValue 変数の値が設定されていないためです。
ノード内のロジックの実行
作成されたノードは、inputTrigger という名前の ControlInput がトリガーされると、2 つの文字列を連結させてそれらを 1 つの文字列として出力します。これを行うには、ControlInput inputTrigger の割り当てを行うラムダ式内にロジックを追加します。
例えば、コードフロー内で、この単純な操作 (myValueA + myValueB) を追加します。
Note
値は入力ポートから取得されます。
flow.GetValue<string>(myValueA) + flow.GetValue<string>(myValueB) + "!!!";
コードは以下のようになります。
using System;
using Unity.VisualScripting;
public class MyNode : Unit
{
[DoNotSerialize]
public ControlInput inputTrigger;
[DoNotSerialize]
public ControlOutput outputTrigger;
[DoNotSerialize]
public ValueInput myValueA;
[DoNotSerialize]
public ValueInput myValueB;
[DoNotSerialize]
public ValueOutput result;
private string resultValue;
protected override void Definition()
{
//inputTrigger ポートがトリガーされた時にノードアクションを実行するラムダ式
inputTrigger = ControlInput("inputTrigger", (flow) =>
{
//myValueB と連結させることで、resultValue を myValueA からの入力値と等しくします。
resultValue = flow.GetValue<string>(myValueA) + flow.GetValue<string>(myValueB) + "!!!";
return outputTrigger;
});
outputTrigger = ControlOutput("outputTrigger");
myValueA = ValueInput<string>("myValueA", "Hello ");
myValueB = ValueInput<string>("myValueB", String.Empty);
result = ValueOutput<string>("result", (flow) => resultValue);
}
}
Relation の追加
Relation は、ノードがその内部フローを表示する方法です。Relation を設定しないと、ノードを制御ポートに接続する時に視覚的な問題が発生する可能性があります。ノードに追加できる Relation には、以下の 3 つのタイプがあります。
- Assignment: 必要なデータを出力するために実行される必要があるポートを表します。
- Succession: 入力ポートから出力ポートへの実行パスを表します。Succession を設定しないと、グラフ内で Dim オプションが有効になっている場合に、接続されたノードがグレー表示されます。ノート: 視覚的な表示に関わらず、実行は続行されます。
- Requirement: 制御入力ポートの実行に必要なデータを表します。
using System;
using Unity.VisualScripting;
public class MyNode : Unit
{
[DoNotSerialize]
public ControlInput inputTrigger;
[DoNotSerialize]
public ControlOutput outputTrigger;
[DoNotSerialize]
public ValueInput myValueA;
[DoNotSerialize]
public ValueInput myValueB;
[DoNotSerialize]
public ValueOutput result;
private string resultValue;
protected override void Definition()
{
inputTrigger = ControlInput("inputTrigger", (flow) =>
{
resultValue = flow.GetValue<string>(myValueA) + flow.GetValue<string>(myValueB) + "!!!";
return outputTrigger;
});
outputTrigger = ControlOutput("outputTrigger");
myValueA = ValueInput<string>("myValueA", "Hello ");
myValueB = ValueInput<string>("myValueB", String.Empty);
result = ValueOutput<string>("result", (flow) => resultValue);
Requirement(myValueA, inputTrigger); //ノードの処理に myValueA の値の設定が必要であることを表示するため。
Requirement(myValueB, inputTrigger); //ノードの処理に myValueB の値の設定が必要であることを表示するため。
Succession(inputTrigger, outputTrigger); //入力トリガーポートの入力が出力トリガーポートの出口から出ることを表示するため。Succession を設定しないと接続されたノードがグレー表示されますが、実行はされます。
Assignment(inputTrigger,result);//inputTrigger が結果の文字列出力にトリガーされた時に記述されたデータを表示するため。
}
}
このカスタムノードを実行すると最終的な結果は以下のようになります。
ノードにドキュメントを追加する
ノード上にドキュメントを追加することは必須ではありませんが、ユーザーがノードの目的を理解するために役立ちます。
ファジーファインダーと Graph Inspector の両方で読めるポートの概要を追加するには現在使用中の Unity 用に新しい C# スクリプトを作成し、それを Editor フォルダー 内に配置してください。MyNodeDescriptor という名前の C# スクリプトを作成し、その中に以下のコードをコピーアンドペーストしてください。
using Unity.VisualScripting;
[Descriptor(typeof(MyNode))]
public class MyNodeDescriptor : UnitDescriptor<MyNode>
{
public MyNodeDescriptor(MyNode unit) : base(unit) {}
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
{
base.DefinedPort(port, description);
switch (port.key)
{
case "inputTrigger":
description.summary = "Trigger the concatenation of the myValueA with the myValueB and return the result string on the Result port.";
break;
case "myValueA":
description.summary = "First string value for the returned result of myValueA + myValueB.";
break;
case "myValueB":
description.summary = "Second string value for the returned result of myValueA + myValueB.";
break;
case "outputTrigger":
description.summary = "Execute the next action after myValueA and myValueB concatenation.";
break;
case "result":
description.summary = "The result string obtained from myValueA and myValueB concatenation.";
break;
}
}
}
グラフ内でノードを選択すると、Graph Inspector にそのノードのポートの説明が表示されます。
ノードのカスタマイズ
ノードをカスタマイズすると、グラフ内で何が起こっているかをユーザーが理解するために役立ちます。ノードをカスタマイズするには、それに属性を設定する必要があります。以下は、ノードの見た目を変更するために使用できる属性のリストです。
Node class 属性
この属性はノードをカスタマイズをするために使用され、ノードの前に記述されます。
属性: [UnitTitle("YourTitle")]
説明: クラス名以外のものを使用したい場合のノードのタイトルです。
属性: [UnitShortTitle("YourShortTitle")]
説明: UnitShortTitle はノード上に表示され、Graph ビュー内のタイトルを非表示にします。
属性: [UnitSubtitle("Your Subtitle")]
説明: 現在のノードタイトルの下に表示される、ノードのサブタイトルです。
属性: [UnitCategory("FirstLevel\SecondLevel")]
説明: ファジーファインダーでノードを見付けるための仮想パスです。
Note
ファジーファインダーを更新してノードをファインダー内に再配置するには、ノードを再生成する必要があります。
属性: [TypeIcon(typeof(GameObject))]
説明: Visual Scripting のアイコンライブラリからアイコンを取得します。各種アイコンはunity タイプによってライブラリ内に保存されています。
Note
この属性から独自のカスタムアイコンを取得することはできません。
Port 属性
Port 属性は、ノードクラス内の ControlInput、ControlOutput、ValueInput および ValueOutput 変数の初期化の上に配置される必要があります。
public class MyNode : Unit
{
[DoNotSerialize] // シリアル化すべきでないデータをシリアル化しないようにするための、必須の属性です。
[PortLabelHidden] // デフォルト入力と Output triggers のラベルは通常非表示にするため、ポートラベルを非表示にします。
public ControlInput inputTrigger;
属性: [DoNotSerialize]
Before: 該当なし
After: 該当なし
説明: 全てのポートに必須の属性です。シリアル化するべきでないデータがシリアル化されないようにするために必要です。
属性: [PortLabelHidden]
説明: ポートアイコンの横のテキストラベルを非表示にします。
Note
ラベルが非表示にならない場合は、ポート変数を Definition: メソッド内のキーと確実に同じにしてください。
例:
myValueA = ValueInput<string>("myValueA", "Hello ");