【Unity】ノードベースの会話システムパッケージを開発してみた！

# 今回開発したもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3083521/bd357503-dbb4-1f09-8fe9-42322298cc4d.png)

GraphViewを用いた、会話システムです。
※今回の記事は序盤パッケージの紹介をして、最後に作成秘話を話します。

## 注意！
このパッケージは、正式リリースされていません。
また、安全性を保障することもできません。

加えて、少なくとも作成者の就活が終わるまでは二次配布、二次加工を禁止します。

## ダウンロード

https://github.com/PrashaltGames/Unity-ConversationGraph

# パッケージ紹介
## 使い方
1. まず、Project WindowでConversation Graph Assetを作成します。
2. このアセットをダブルクリックすると、専用のWindowが開きます。
3. ノードベースで会話を構築します。
4. Conversation System UGUIコンポーネントをシーンに配置し、必要なUIや設定を行います。
5. Conversation System UGUIコンポーネントにアクセスして、`StartConversation`メソッドを使用すると始まります。

### 使い方に関する動画
※無編集なので、見にくいと思いますが、、、編集する気力がないので許してください。
※この動画は執筆時点より後のバージョンで撮影されており、GraphInspectorが実装されています。

https://www.youtube.com/watch?v=cDWX_ejsvd8

## 対応する環境
- Unity 2021 LTS or newer (.NET Frameworkを使った環境が必要)
    - サポート自体はこのバージョンだが理論的にはもう少し前でも動くはず…？未検証。
- Input Managerを使った環境
    - 詳しくは後述
- uGUI

## 出来ること
- 選択肢を表示してそれに伴ったテキストを表示すること。
- テキストをアニメーション（ON/OFF可）で表示すること。
- クリックして次のテキストを表示すること。
- クリックせずに指定したミリ秒で、次のテキストを表示すること。

## 実装予定のこと
- ~~テキストがすべて出ていない状態でクリックすると、テキストがすべて表示されるようにする~~
    - 実装済み
- ConversationGraphAsset専用のカスタムインスペクターの作成
- UI Elements, Input Sysytemの対応

## 既知の不具合
- ~~Startノードを削除できてしまう不具合~~
    - ~~不格好ではあるが、~~ いい感じに修正済み
- ~~再生する（コンパイル…？）専用のWindowの表示がなくなってしまう不具合~~
    - ~~対象法として、一度閉じて再度開き直すと治ります。~~
    - 修正済み

## カスタムについて
本パッケージは汎用性を高めるために、`ConversationSystemBase`という抽象クラスを用意しています。
これを継承し、このクラスが提供する下記のイベントに関数を入れることでオリジナルの挙動をすることができます。
ぜひご活用ください。

### 提供されるイベント
※パッケージバージョン、0.2.1で名称がアクションからイベントに変更されています。
- OnNodeChangeEvent : テキストのノード（SelectNode以外）に切り替わったときに発火するイベント
- OnShowOptionsEvent : SelectNodeに切り替わったときに発火するイベント
- OnConversationFinishedEvent : 会話全てのノードが終了したとき発火するイベント

# 作成秘話
制作期間は5日。毎日4~5時間ほど。恐らくかかった時間は20時間ぐらい。
## 作成するきっかけ
少し前から個人的に開発するゲームでテキストを表示するシステム構築したいと思っていた。
テキストベースのアセットなどは既存にあったがノードベースが見当たらなく、欲しくなった。

そこに、GraphViewの情報が入ってきて自分で作ろうということに。
本来、自作ゲームを優先して開発してその後作成する予定だったが、先輩に今作っているものに欲しいと言われてこちらを優先することにした。

## こだわり
### 拡張性
設計の拡張性の高さはこだわり。
もともとUI ElementsにもUGUIにも、はたまたInput SystemにもInput Managerにも対応させたいと思っており、そのために抽象クラスを継承してコンポーネントを作ったほうが良いと思ってこのような設計となった。

ただ、UI ElementsとInput Systemには対応させていない。今後対応予定。

### アロケーション
最近、凄い方の記事を見ているとアロケーションという文字が凄く多いように感じる。
その意味を最近やっと理解し始めたので、アロケーションがなるべくないように実装した。

例えば、ToListを使わないようにしたことだ。
これによって、IEnumerableさんと仲良くすることになり、苦戦した。

### IReadOnlyList
なるべくIReadOnlyListを使うことで、カプセル化を徹底した。
これもまた、IEnumerableさんが数多く顔を出してくる原因になっている。

ていうかほぼコイツが元凶。

### UX面で
ノードベースでよくあるのが、ノードが多すぎて分からんというパターン。
なるべくこれをなくすように、ひとつのノードで複数のテキストを保存できるようにした。

これによって若干オリジナルのコンポーネントを作る難易度が上がっているのが難点。
ただ、メリットの方が明らかに多いのでこうした。

# 振り返って
参考にした記事が素晴らしく、実はGraphViewの理解度は高くないというのが正直なところ。
ソースコードを読んだら分かるがコピペした部分も多々ありもっと理解を深めたい。

UI Elementsもまともに触るのが初めてで苦戦した点だった。
ただ、Webの開発を少ししていたのもあってUI構築は特に苦戦しなかった。

GraphViewは今後サポート終了予定で、GraphTools Foundation(GTF)に移行予定らしい。
移行するときはこのパッケージも移行したいと思っている。

# 最後に
バグ、不具合、追加してほしい機能あればX（旧Twitter）のDMないしはGitHubのIssueで教えてください。
一番下に参考にした記事を貼っておきます。本当にありがとうございました。

# 参考にした記事

https://creator.game.cyberagent.co.jp/?p=6903

https://light11.hatenadiary.com/entry/2023/04/03/203231

https://hirukotime.hatenablog.jp/entry/2022/11/11/201335

https://light11.hatenadiary.com/entry/2023/05/15/190715

これ以外も多くありますが、全て列挙するとキリがないので、主としてみた記事を貼りました。
改めてありがとうございます。