【Unity】GraphViewで変数機能を実装したい【Blackboard】

# はじめに
どうも！伸び代しかない新米Unityエンジニアのあつあつ([@kaidoatsuya](https://x.com/kaidoatsuya))です！
今回はGraphViewというノードベースツールを作るUnityの機能でBlackboradという機能の紹介とTipsをまとめてみたいと思います！

# GraphViewとは
GraphViewはShaderGraphのようなノードベースのツールを制作するためのAPI群です。
実際にゲーム開発現場でも使用されています！詳しくは以下の記事をご覧くださいっ！

https://media.colorfulpalette.co.jp/n/nf16e36c291b0

# Blackboardとは
ShaderGraphには変数機能が存在します。
下のようなUIみたことありませんか？これをBlackboardといいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083521/86de19ca-b97c-4a71-b619-672608bc68d9.png)

## 追加の仕方
BlackboardをGraphViewのWindowに追加するには以下のコードを記載すればOKです。
```Csharp
// 独自のグラフビューのクラスの中という前提
// コンストラクタやInitializeメソッドの中での初期化処理を想定
var blackboard = new Blackboard();
Add(blackboard);
```

簡単ですね。Blackboard自体もGraphElementというGraphViewのノードなどが継承しているクラスを継承しているため、扱いとしてはノードと大きく変わりません。

:::note info
今回は紹介しませんがBlackboardはGraphViewと別のWindowとしても作成できます。
`GraphViewBlackboardWindow`などを参照してください。
:::

# Blackboardのために用意されたGraphElement
Blackboard用に提供されているGraphElementが3つ存在します。

- BlackboardRow
- BlackboardField
- BlackboardSection

それぞれ、みていきましょう。

### BlackboardRow
以下のC#コードでGraphViewに追加してみます。
```Csharp
 var space = new BlackboardRow(new Button() { text = "item"}, new Button(){text = "propertyView" });
 blackboard.Add(space);
```
見た目はこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083521/7b661253-3c38-45f8-b4ec-59fc3d34089c.png)

このGraphElementはいくつかの変数をひとまとめするのに使えそうですね。
ほかのGraphElementと組み合わせるとさらにそれっぽくなります。あとで紹介します。

### BlackboardField
以下のC#コードでGraphViewに追加してみます。
```csharp
var field = new BlackboardField()
{
    text = "Field",
    typeText = "TypeText"
};
blackboard.Add(field);
```
見た目はこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083521/30a64e3b-187b-4919-bf9e-f9c5a5c689b1.png)

みたことありますね。あれです。あれ。
ダブルクリックをすると`Field`と書いてある部分が編集できたり、あれの機能がもともとからあるのは嬉しいですね。
後から紹介しますが、ドラッグ＆ドロップの機能も存在します。

### BlackboardSection
以下のC#コードでGraphViewに追加してみます。
```csharp
var row = new BlackboardSection() {title = "Section"};
blackboard.Add(row);
```
見た目はこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083521/8fa047db-5b59-4a97-831d-c922a122d695.png)

はい。Sectionでした。特に何もいうことはありません。


## 組み合わせてみる
以下のようなコードでFieldとRowを組み合わせてみます。
```csharp
var field = new BlackboardRow(new BlackboardField()
        {
            text = "村人A", 
            typeText = "Person"
        }, personProperty);
```

見た目はこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083521/aca21d08-7054-405c-8847-e8e792596fc2.png)

それっぽくなってきましたね！
このようにRowとFiledを組み合わせると凄く整ったUIになるように設計されています。

# Tips
ここからは触って気がついたTipsについて紹介していきます！

## BlackboardFieldをGraphViewへドラッグ＆ドロップをしたい
通常のドラッグ＆ドロップのフローとほぼ同じです。

https://light11.hatenadiary.com/entry/2024/04/17/195943

ただし、`DragAndDrop.GetGenericData(KEY);`で行うデータ取得にポイントがあります。
もともとBlackboardFieldにはドラッグ&ドロップ機能があるため、KEYがこちら側で設定できません。
キーは`"DragSelection"`という文字列で固定されています。またデータはBlackboradFieldのGraphElementが返ってくるので、VisualElement.userDataにノード用の情報を格納しておくと、生成が楽かもしれませんね。

## BlackboardのプラスボタンからFieldを追加したい！
こちらは、`GenericMenu`を利用すれば可能です。本題からそれるため詳しくは説明しませんが、コンテキストメニューを作ることが可能なAPIです。

https://docs.unity3d.com/ja/2022.3/ScriptReference/GenericMenu.html

# おわりに
最近、記事を書いておらずでしたが、久々にBlackboardがあることを個人開発中に知ったので、キャッチアップしてみました。
ついでに記事を執筆！最高〜！
最近は内定者アルバイトや個人開発で、キャッチアップが疎かになっていますが、少しずつ並行できる力をつけていきたいです