【Unity, UIElements】GraphViewと戯れる

クライアントエンジニアの穴うなぎです。

今回のブログでは、UIElementsの勉強を兼ねてGraphViewを触った結果得られた知見を紹介します。

GraphViewはEditor上にノードエディタを作成できる機能です。ShaderGraphやVFXGraphはこのAPIを使って実装されています。

本記事では基本的なGraphViewの使い方については触れませんのでご了承ください。

GraphViewを初めて触る方はこちらの記事や動画を参考にされることをおすすめします。

GraphView完全理解した(2019年末版) - Qiita
UNITY DIALOGUE GRAPH TUTORIAL - Setup - YouTube

使用したUnityのバージョンは2019.3.6f1です。

今回作成したノードエディタの紹介

マインドマップ的なノードエディタを作成してみました。

このノードエディタは以下の機能を持ちます。

  • Outputが1つあるEntryPointノードを起点に、子ノードをつなげてグラフを作成できる
  • 各ノードはキーワードを入力するためのTextFieldを持つ
  • 各ノードは表示色を変更できる
  • ノードの編集UIは折りたたみが可能で、折りたたむと1行になる
  • グラフの保存・読み込みができる

GraphViewの知見

Nodeに置くVisualElementは適切なContainerへ

NodeはhogeContainerという命名のVisualElementプロパティを持っています。
それぞれのhogeContainerはEditor上の位置に対応しています。
hogeContainerの階層構造は以下のとおりです。

Editor上ではhogeContainerの位置関係は以下のようになっています。

一部のhogeContainerは内部的に子要素の型を判定して行われる処理があるため、適切なContainerに要素を配置しなかった場合は予期しない挙動をすることがあります。(後述)
基本的にはPortをinputContainer, outputContainerに配置し、パラメータ設定の要素をextensionContainerに配置するといいでしょう。

デフォルトのCollapseボタンは地味に不便

Nodeにはデフォルトでノードを開閉するボタンが備わっています。
このボタンは接続を持つPortがある場合にボタンを無効にする処理が備わっています。
今回はNodeをコンパクトにしたかったので、接続を持つPortがあっても閉じることのできるノード開閉ボタンに置き換えました。
Nodeの開閉はexpandedプロパティのsetterから実行できます。

PortをinputContainer、outputContainer以外に置かない

inputContaineroutputContainer以外にPortを置くと、Editor上でNodeを削除した際に接続されたEdgeを消す処理が動かない、などの予期しない挙動をします。
そのため、PortはinputContaineroutputContainerに置くのが無難です。
今回はtopContainertitleContainerInsert()してコンパクトにしてみました。

また、今回作成したグラフではPortの型が1つしかなくLabelが不要なので削除しました。
Portに表示されるLabelの値はportNameプロパティからアクセスできます。

VisualElementのstyleを動的に変えられる

styleプロパティに直接アクセスすることでVisualElementの色をスクリプトから変更できます。
今回作成したグラフではColorFieldのCallbackでノードの色を変えています。

TextFieldが日本語入力を受け付けるようにするためには設定が必要

TextFieldはデフォルトではIMEオフの入力のみを受け付けますが、以下のようにCallbackを登録するとIMEによる入力が可能になります。

グラフの保存と読込の実装

グラフをScriptableObjectに保存・読み込みする機能を実装しました。
サンプルコードを以下に示します。
NodeにGUIDを持たせてやるとNodeとEdgeの管理が容易になります。

GraphSaveUtility.SaveGraph()ではGraphViewから取得したNodeとEdgeをScriptableObjectに保存します。
GraphSaveUtility.LoadGraph()ではScriptableObjectのデータを基に、GraphViewの初期化、Nodeの生成、Edgeの生成を行います。

おわりに

今回GraphViewを触って「かなり遊べるな!」という印象を受けました。
ノードに配置する要素の自由度が高く、Edgeの拘束も自由に設定できるので多様なグラフの表現が可能に思いました。
みなさんもぜひGraphViewを触ってみてはいかがでしょうか。

参考文献

UNITY DIALOGUE GRAPH TUTORIAL - Setup - YouTube
GraphView完全理解した(2019年末版) - Qiita
Unity - Manual: UIElements Developer Guide
XAMLとか知らねぇよ!!C#だけでUIElement式エディタ拡張をする入門~style編~ - Qiita