【Unity】xNode入門②|Node同士で値を受け渡す|Buttonで足し算・引き算を切り替える
前回は、xNodeをUnityに導入し、以下を確認しました。
Graphを作る
Nodeを作る
InputとOutputを追加する
Node同士をConnectionでつなぐ
Graph内のNodeをC#から読み取る
ただし、前回の段階では、Node同士を線でつないでも、値が自動的に次のNodeへ渡るわけではない、というところで終わっています。
今回はその続きとして、Connectionを使ってNode同士で値を受け渡す方法を確認していきます。
さら、Buttonを使って、足し算をするか、引き算をするかを切り替える簡単なSampleを作ってみます。
1.前回のおさらい
前回は、次のようなGraphを作りました。

NumberNodeには、以下の Output を追加、
[Output]
public int output;DisplayNodeには、以下の Input を追加しました。
[Input]
public int input;これによって、Output Port と Input Port を Connection でつなぐことができました。
しかし、この線をつないだだけでは、
NumberNodeの10
↓
DisplayNodeへ自動的に10が入るという動作にはなりません。
そこで今回は、実際に接続先から値を取得する仕組みを作っていきます。
2.xNodeで値を受け渡す
2-1.値の受け渡しフロー
xNodeでは、Output側が勝手に値を送り続けるというより、Input側が値を必要としたときに、接続先のOutputへ値を取りに行くと考えると分かりやすいです。

DisplayNode
「inputの値が欲しい」
│
▼
Connectionを確認
│
▼
NumberNode
「Valueを返します」
│
▼
10この仕組みを作るときに、主に使うのが、
GetValue()
NodePort
GetInputValue<T>()
です。順番に確認していきます。
2-2.NumberNodeから値を返す
まず、前回作成した NumberNode.cs を修正します。
現在は、次のような形になっています。
作成済みのコードに、GetValue() を追加します。
using XNode;
public class NumberNode : Node
{
public int value = 10; //記述済み
[Output]
public int output; //記述済み
public override object GetValue(NodePort port)
{
return value;
}
}■ GetValueとは?
今回追加したのが、以下の関数です。
public override object GetValue(NodePort port)
{
return value;
}GetValue() は、そのNodeのOutputから値を取得するときに呼ばれるメソッドです。
今回のNumberNodeでは、
return value;としているため、NumberNode の value が返されます。
たとえば、Value = 10 に設定してあれば、
Outputから値を取得 → 10を返す
という動作になります。
これでNumberNodeは「接続先から要求されたときに値を返せるNode」になりました。
■ NodePortとは?
GetValue() の引数を見ると、 NodePort port が指定されています。
NodePort は、Node についているPortの情報を表します。つまり、
public override object GetValue(NodePort port)は、「どのPortから値を求められたのか」を確認できるようになっています。
今回の NumberNode は Output が1つしかないので、
return value;だけで問題ありません。ただし、将来的に、
Output A
Output B
Output C
のように複数のOutputを持つNodeを作る場合は、どのPortから呼ばれたのかを確認して、返す値を切り替えることもできます。
今回は「NodePortはPortの情報を扱うもの」くらいに覚えておけば大丈夫です。
2-3.DisplayNodeで接続先の値を取得する
次に、前回作成した DisplayNode.cs を修正します。
using XNode;
public class DisplayNode : Node
{
[Input]
public int input; //記述済み
public int GetInputNumber()
{
return GetInputValue<int>("input", input);
}
}以下の関数を追加しました。
public int GetInputNumber()
{
return GetInputValue<int>("input", input);
}■ GetInputValue とは?
GetInputValue<型名>() を使うと、Input Portに接続されているNodeから値を取得 することができます。
今回の場合、以下のように記述しています。
GetInputValue<int>("input", input)<int> は「int型の値を取得する」いう意味です。
最初の "input" は、値を取得するInput Portの名前です。
つまり、
[Input]
public int input;の input を指定しています。
2つ目の、input は、Input Portに何も接続されていない場合に使う値です。
そのため、
Connectionあり → 接続先のOutputから値を取得
Connectionなし → DisplayNode自身のinput値を使う
という動きになります。

2-4.前回のGraphTesterで確認
前回作った GraphTester.cs を利用して、DisplayNodeが受け取った値をConsoleに表示してみます。
GraphTesterを次のように変更します。
using UnityEngine;
public class GraphTester : MonoBehaviour
{
public SampleGraph graph; //Graphのインスペクターから割り当てる
void Start()
{
foreach (var node in graph.nodes)
{
if (node is DisplayNode displayNode) //nodeがDisplayNode型の場合
{
Debug.Log(
"DisplayNodeが受け取った値:" +
displayNode.GetInputNumber()
);
}
}
}
}NumberNodeの Valueを 10 に設定し、
NumberNode 〇⇔〇 DisplayNode、と接続した状態で

Play を押して、Consoleに以下のように表示されれば成功です。

これで初めて、
NumberNode Value = 10
Connection
DisplayNode Input = 10
という値の受け渡しができました。
2-5.Connectionを外すと
ここで、NumberNode と DisplayNode の Connection を外してみましょう。
さらに、DisplayNodeのInputに、5を設定します。

その状態でもう一度Playすると、以下のように表示されます。

これは、
GetInputValue<int>("input", input)の2つ目の input が使われているためです。つまり、
接続されている → 接続先の値を使う
接続されていない → 自分に設定されている値を使う
ということです。
3.サンプル:計算システム作成
値の受け渡しが分かったところで、少し実践的なNodeを作ってみます。
今回は、2つの値を受け取って足し算する、AddNode を作ります。
3-1.足し算を行う AddNode の作成
新しくスクリプトファイル:AddNode.cs を作成し、次のように記述します。
using XNode;
public class AddNode : Node
{
[Input] public int a; //int型の入力ポート a
[Input] public int b; //int型の入力ポート b
[Output] public int result; //int型の出力ポート result
public override object GetValue(NodePort port) //ノードの実行
{
int valueA = GetInputValue<int>("a", a); //入力ポート a の値を取得
int valueB = GetInputValue<int>("b", b); //入力ポート b の値を取得
return valueA + valueB; //a と b の値を足して返す
}
}コードの解説
AddNodeには、
[Input] public int a;
[Input] public int b;という2つのInputがあります。
[Output] public int result;で、計算結果を出力するPortを作っています。
GetValue() の中では以下のコードで、aとbに接続されているNodeから値を取得しています。
int valueA = GetInputValue<int>("a", a);
int valueB = GetInputValue<int>("b", b);最後に、
return valueA + valueB;として、足し算の結果を返しています。
3-2.引き算を行う SubtractNode の作成
次に、引き算を行うNodeも作ります。
新しく、スクリプトファイル:SubtractNode.cs を作成します。
using XNode;
public class SubtractNode : Node
{
[Input] public int a; //int型の入力ポート a
[Input] public int b; //int型の入力ポート b
[Output] public int result; //int型の出力ポート result
public override object GetValue(NodePort port) //ノードの実行
{
int valueA = GetInputValue<int>("a", a); //入力ポート a の値を取得
int valueB = GetInputValue<int>("b", b); //入力ポート b の値を取得
return valueA - valueB; //a と b の値を引いて返す
}
}基本的な構造はAddNodeとほぼ同じです。
違うのは最後の return の部分だけです。
return valueA - valueB;これで、
足し算を行う AddNode
引き算を行う SubtractNode
ができました。
3-3.Graphを組み立てる
今回は、足し算と引き算を行うSampleを作るため、新しいGraphを用意します。
新に CalculationGraph.cs を作成し、次のように記述します。
using UnityEngine;
using XNode;
[CreateAssetMenu]
public class CalculationGraph : NodeGraph
{
}Projectウィンドウで右クリックし、Create → Calculation Graph からGraphアセットを作成します。

今回は、この CalculationGraph の中に、
NumberNode × 2
AddNode
SubtractNode
を配置します。

今回はNumberNodeを2つ用意します。
それぞれの value の値をたとえば、以下のように指定します。
NumberNode A Value = 10
NumberNode B Value = 3
さらに、AddNode と SubtractNode に対して、それぞれ次のように接続します。
NumberNode A の Output を、AddNode の A と SubtractNode の A に接続
NumberNode B の Output を、AddNode の B と SubtractNode の B に接続
イメージとしては、次のような形です。

これで同じ2つのNumberNodeを使って、
10 + 3
10 - 3の両方を計算できるGraphになります。
3-4.Buttonを用意する
次はUnity側にButtonを作ります。
Canvasの中にButtonを2つ作成します。
1つ目のテキストを「たし算」、2つ目のテキストを「ひき算」としておきます。

この2つの Button から、xNodeの AddNode と SubtractNode を呼び分けます。
3-5.ButtonからxNodeを利用する
今回は新しく、スクリプトファイル:CalculationController.cs を作ります。
public class CalculationController : MonoBehaviour
{
public CalculationGraph graph; //CalculationGraph型の変数 graph
public void Add()
{
foreach (var node in graph.nodes) //graph.nodes の中身を順番に取り出す
{
if (node is AddNode addNode) //node が AddNode 型の場合
{
//addNode の result ポートの値を取得
int result = (int)addNode.GetValue(addNode.GetOutputPort("result"));
Debug.Log("たし算の結果:" + result);
}
}
}
public void Subtract()
{
foreach (var node in graph.nodes)
{
if (node is SubtractNode subtractNode)
{
//subtractNode の result ポートの値を取得
int result = (int)subtractNode.GetValue(subtractNode.GetOutputPort("result"));
Debug.Log("ひき算の結果:" + result);
}
}
}
}このスクリプトでは、
public void Add()と、
public void Subtract()という2つのメソッドを作っています。
Addでは、
if (node is AddNode addNode)によってGraph内のAddNodeを探しています。そして、
addNode.GetOutputPort("result")で、AddNodeの result Portを取得しています。
そのPortを、
addNode.GetValue(...)へ渡すことで、AddNodeの計算結果を取得しています。
今回は、10 + 3 なので、13 が返ります。
Subtractも同じ考え方です。
Graph内からSubtractNodeを探し、
subtractNode.GetValue(...)によって計算結果を取得します。
今回は、10 - 3 なので、7 が返ります。
3-6.ButtonのOn Clickに登録する
CalculationController.cs を、空のGameObjectなどにアタッチします。
サンプルでは、スクリプトファイルをそのままヒエラルキー上に配置して、オブジェクト化しています。
※最近のアップデートでこの機能が使えるようになったようです。
InspectorのGraph欄には、今回使用している CalculationGraph を登録します。

AddButtonを選択し、Buttonコンポーネントに以下を指定
On Click():CalculationControllerを登録
関数:CalculationController → Add()

SubButtonを選択し、Buttonコンポーネントに以下を指定
On Click():CalculationControllerを登録
関数:CalculationController → Subtract()

これで準備完了です。
3-7.実行してみる
UnityをPlayします。
たし算 のButtonをクリックします。Consoleに、
たし算の結果:13と表示されれば成功です。
同様にひき算 のButtonをクリックします。Consoleに、
ひき算の結果:7と表示されます。
これで、2つの処理を、Buttonから切り替えられるようになりました。
3-8.フローの確認
ここで今回の処理の流れを確認します。
今回のSampleでは、
たし算Button → Add()
ひき算Button → Subtract()
という形で、どの処理を使うかはButton側で分岐しています。
一方、xNode側では、下の図のように

値や計算の関係 をGraphとして持っています。つまり、
Unity UI → どの処理を実行するか決める
xNode → その処理に必要な値やNodeの関係を管理する
という役割分担になっています。
この形を見ると、第1回で説明した「xNodeはNodeを置けば自動的にゲームが動くツールではない」という意味も分かりやすくなります。
もう1つ重要なのが、値を取得する順番です。
見た目では、
10 → AddNode
3 → AddNodeと値が流れているように見えます。
しかし、実際のイメージは少し違います。
たとえばAddButtonを押した場合、次のような流れとなります。

つまり、必要になったタイミングでConnectionをたどり、接続先の値を取得しているということです。
この考え方は、xNodeを理解するうえで非常に重要です。
18.今回のまとめ
今回は、xNodeでNode同士の値を受け渡す方法を確認しました。
ポイントは次の通りです。

次回は、今回のような単純な計算処理から一歩進めて、

上の図のような、ゲームで使えるNodeの流れや分岐について確認していきます。
▼ Unity初心者向け記事まとめはこちら
こちらのマガジン「ミニゲーム作成講座 全8回セット」でもシーンの切り替えなどを活用して、初心者でも知識ゼロから作れるミニゲーム作成講座を紹介しています。

さらにステップアップの「スマホで遊ぶジャンプゲーム 8回セット」のマガジンもぜひご活用ください。

ファイブボックスでは、スクラッチやUnityの個別指導のオンラインレッスンを行っています。
ご興味のある方は当サイト、オンラインレッスンから、無料体験授業へお問い合わせ下さい。
いいなと思ったら応援しよう!
よろしければ応援お願いします! いただいたチップはクリエイターとしての活動費に使わせていただきます!