Dialogue System for Unityを導入してみる

ゲームでよくある会話や、カットシーンを作れる「Dialogue System for Unity」というアセットを導入してみる記事です。

とにかく機能が豊富なアセットなんですが日本語での導入記事が少なく、これはどうやるんじゃ！と思ってもドキュメントを読み込むしか手段がなかったので、誰かの手助けになればと思い記事を書いた次第です。
自分のメモも兼ねています。
（すべての動作を把握しているわけではないので、間違いなどあるかもです。その場合はご指摘ください！）

:::note
環境
Unity：2021.2.0f1
Dialogue System for Unity：2.2.22
:::

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Dialog System for Unityアセットをお試し中です。<br><br>なるほど、会話はグラフ的に作れて...<br>メッセージが出る部分は所定のコンポーネントを張り付けたオブジェクトを設定する感じですね。<br><br>組み込まれているものを改造して使う感じのようです。<br>もっとできることを調査せねばー<a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://t.co/l6hDbHV5kx">pic.twitter.com/l6hDbHV5kx</a></p>&mdash; asiram / unityゲーム開発 (@asiramasiram) <a href="https://twitter.com/asiramasiram/status/1456226472293662728?ref_src=twsrc%5Etfw">November 4, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# Dialogue System for Unityとは
会話ウィンドウの仕組みや、クエストシステムなどが作れるアセットです。

https://assetstore.unity.com/packages/tools/ai/dialogue-system-for-unity-11672

公式ドキュメント：http://www.pixelcrushers.com/dialogue_system/manual2x/html/

**いいところ**

- 専用エディタで会話を作成可能
- 会話の任意のタイミングで、カメラ操作やフェードイン/アウトなど演出に便利な様々な操作が可能
- ローカライズにも対応
- サードパーティ製のアセットやライブラリとの連携あり（程度は様々な模様）
  - TextMeshProやI2Localizationなど、かなりの数のアセットに対応しています。
- Luaで挙動を制御可能（ぜんぜん把握していません）

**微妙なところ**

- スクリプトの量がかなり多い
  - 人によるとは思いますが、やりたいことに対して余分な機能が多くなる可能性が高いです
- すべて使いこなそうとすると、学習コストがある程度かかる（ほかのアセットに比べて）
- 日本語の解説がありません！（そりゃそうだ）
  
# Dialogue System for Unityを導入してみる
簡単な会話ができるようにしてみましょう。
基本的には、本家の[Getting Started](https://www.pixelcrushers.com/dialogue_system/manual2x/html/quick_start.html)に従う形になります。
最初はなぜかデフォルト動作である選択肢が出てくる会話パターンです。

アセットのインポート手順は省略します。
いつも通り、Package Managerから選択、ダウンロード後にインポートしてください。

## データベースを用意する
まずは会話データを格納するDialog System専用のデータベースを作成します。
一つのデータベースの中に複数の会話を格納することができます。
データベースを作成する前に、シーンにDialogue Systemの動作を管理するオブジェクトを配置しましょう。

Dialogue Systemをインポート後にフォルダ構造を変えていなければ、`Plugins/Pixel Crushers/Dialogue System/Prefabs`に`Dialogue Manager`というプレハブがあります。
このプレハブをヒエラルキーにドラッグ＆ドロップで配置しましょう。
（雑なスクショで申し訳なしです）
![スクリーンショット 2021-11-05 164727.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/60c13110-c306-5f62-dc3c-c0356d548ecc.png)

次に、追加されたオブジェクトの`DialogueSystemController`の`InitialiDatabase`横にある`Create`ボタンを押してデータベースを作成しましょう。
![スクリーンショット 2021-11-05 170129.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/ec45b4d6-7833-4f08-8b64-efd982aeabe3.png)

どこに保存するか聞かれるので、適当な場所を指定しましょう。
とりあえず「DialogueSystemDatabases」というフォルダを作成、その下に「Dialogue Database.asset」(デフォルトの名前)で保存しました。

## 会話の作成
次に、新しいウィンドウ（Dialogueウィンドウ）が開いているはずなので、`Conversations`タブに移動しましょう。
データベースが作られていると先ほどの`Create`のボタンが`Edit`に変わるのでそこからも遷移できます。
作成したデータベースファイルからも遷移できます。

`Conversations`タブに移動したら、「+」ボタンから会話を作成しましょう。
ここで作成される会話は、例えば「NPC1とプレイヤーの会話」のような、複数のセリフのまとまりです。
これだけだとさっぱりした説明ですが、このセリフ中に演出を挟んだり選択肢を追加したり様々なことができます。
![スクリーンショット 2021-11-05 170803.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/f120fb80-fbea-6a13-7c12-d277bd04d223.png)

会話が作成されると、自動的に開始ノードも作成されます。
開始ノードを右クリックして、`Create Child Node`で子ノードを作ります。
![スクリーンショット 2021-11-05 171307.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/bce3f681-3b6b-7468-951d-7b9007036f03.png)

ノードが一つ追加されたはずです。
このノード一つが、ひとつのセリフと考えればOKです。
追加されたノードを選択して、インスペクターの`Dialogue Text`にセリフを入れましょう。
![スクリーンショット 2021-11-05 172323.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/3d896e47-0b63-c84a-5963-ff740612eeed.png)

ついでにもう一つセリフを追加しましょう。
先ほどと同様の手順で、今追加したノードの子ノードを追加しましょう。
そうすると青いノードが追加されたと思います。
これは「Player」のセリフで、灰色のノードは「NPC」のセリフとなっています。
この切り替えはノードの設定で逆にしたりすることができます。
同様にセリフも入力しておきます。
![スクリーンショット 2021-11-05 172819.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/1f094aad-e535-eb40-7fd1-55ce01e4947b.png)

最後に、ヒエラルキーの「Dialogue Manager」を選択して、`Initial database`に今作成したデータベースを割り当てておきましょう（ひょっとしたらもう割り当たっているかもしれないです）。
Auto-Backupなる同じ内容のファイルがありますが、直接作成したほうを指定しましょう。![スクリーンショット 2021-11-05 174138.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/7898297c-b658-5da9-0ee2-6962e6203114.png)

## 会話する対象を追加する
ここまでできたら、会話データが完成したので、会話をしてもらうオブジェクトを作成しましょう。

まずはプレイヤーとなるオブジェクトを作成します。
今回は例に倣い、空のオブジェクトを用意します。
名前はとりあえず「Player」にしました。

次にNPCオブジェクトとして、シーンにCubeを配置します。（cubeじゃなくてもOK：コライダーがついていればよいはず）
追加したcubeに`Dialogue System Trigger`を追加します。
![スクリーンショット 2021-11-05 174540.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/0496b0e6-996f-3118-7792-16999178539d.png)

このトリガーで、会話が始まるように`DialogueSystemTrigger`の`Actions`の`AddAction`ボタンを押して、`Start Conversation`を選択します。
Conversationの項目のドロップダウンから「New Conversations 1」（先ほど作成した会話データ）を選びます。
さらに、`Conversation Actor`に先ほど追加したPlayerを割り当て、`Conversation Conversant`にNPCを割り当てます。

このNPCオブジェクトがどの会話を行い、誰と会話するのかが設定できました。![スクリーンショット 2021-11-05 175012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/8d67c52e-a2a7-c089-9437-a005933eef78.png)

最後に、`Trigger`の設定を`On Start`にして、オブジェクトのStart()メソッドが呼ばれたタイミングでこのトリガーが発火するようにしましょう。
![スクリーンショット 2021-11-05 175448.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/8640835a-d532-2874-a6b0-8e04a5594e54.png)

ここまでできたら再生してみましょう。
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/6a05cd54-fb0c-e4c7-a589-26041196d103.gif)

...なにか動きがぎこちないですが、ちゃんと表示されましたね。

さて、挙動をみるとわかるのですが、最後のプレイヤーのセリフが選択式になっています。
これはDialogue Systemのデフォルトの動作のようです。
正直、選択肢よりは普通に会話ダイアログが交互に表示されるのが一般的かなと思います。
こちらは後でそのように組み替えてみるので、お楽しみに。

## NPCオブジェクトを選択したときに会話を開始するようにする
シーン開始時に会話が始まるように設定していましたが、今度はNPCのオブジェクトをクリックしたときに会話が始まるようにします。

NPCオブジェクトの`DialogueSystemTrigger`コンポーネントの`Trigger`を`On Use`に変更します。
それに加えて、`Usable`というコンポーネントを追加、`Max Use distance`を30に設定します。
これは、カメラから30mまでは話しかけることができる、というような設定です。
これでNPCが選択できるようになりました。
![スクリーンショット 2021-11-05 182520.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/faaf2492-10ba-5a12-fc33-ee6678963526.png)

次にPlayerオブジェクトに`Selector`というコンポーネントを追加します。
その名の通り、会話をする対象を選択するためのコンポーネントです。
このコンポーネントの`Select At`を`Mouse Position`に設定しておきましょう。
こうすることで、マウスによって会話対象を選択することができます。
![スクリーンショット 2021-11-05 182930.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/29aee1b4-7dde-f311-e6c2-a844ae47de18.png)

これで設定は終わりました！
再生してみましょう。
マウスカーソルをcubeの上に持っていくと...NPCの情報が表示されます。（UseDefaultGUIのチェックを外すと出なくなります）
cubeを左クリック...ではなく、右クリックすると会話が始まります。
![ezgif.com-gif-make3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/66a87caa-5795-3be8-dd3b-a20054567755.gif)

# セリフが交互に出るようにする（選択肢ではない方式にする）
最後のセリフが選択式になっていましたが、ここではNPCのセリフ同様にプレイヤー用のセリフもシンプルなウィンドウで表示されるように変更しましょう。

Dialogue Managerオブジェクトの`DialogueSystemController`の設定を二つ変更すればOKです。

- `Subtitle Settings` >`Show PC Subtitles During Line` をチェック
-  `Input Settings` > `Always Force Response Menu`のチェックを外す
![スクリーンショット 2021-11-05 184728.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/675cf513-aedc-ca7a-e4e7-1b7f6045b3dd.png)

これで再生してみましょう。
![ezgif.com-gif-maker4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/3ad6d0aa-c1cc-919b-db29-e23341312b1d.gif)

# 会話レイアウトがどうなっているか見てみる
会話は作れましたが、会話時に表示されるのはデフォルトUIです。
実際に使用するときはどうやって改造するのかをちょっとだけ見てみます。

デフォルトの状態だと、`DialogueSystemController`の`Dialogue UI`の項目に`Basic Standard Dialogue UI`というプレハブが割り当てられています。
ここの設定でレイアウトを決めているようです。
![スクリーンショット 2021-11-05 185940.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/23823d59-7d8e-a4fd-6419-77a769cc1c7a.png)

このプレハブの内容を見てみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/62924/b5093917-a503-c224-a7d9-b472a33bc07b.png)

なるほど、先ほど表示されていたUIがレイアウトされていますね。
各オブジェクトをインスペクターで見てみると、要所要所にDialogue SystemのUI要素を表すコンポーネントが追加されています。
`StandardDialogueUI`は各UI要素を束ねる存在のようです。
`StandardUISubtitlePanel`は、NPCやプレイヤーのセリフを表示するUIのようです。
...などなど。
UIに関しては、公式ドキュメントの[この項目](https://www.pixelcrushers.com/dialogue_system/manual2x/html/dialogue_u_is.html)で解説されています。

実際にDialogue Systemを使用するときは、このプレハブを複製してそれぞれのUIを置き換えていけばよさそうですね。

# まとめ
Dialogue System for Unityを導入し、実際に使用できそうなところまで見てみました。
このほかにも触れられるトピックはうんとありそうです。
演出周りの設定の仕方、ローカライズの方法、クエストシステムについてなどなど...

かなりボリュームがあるアセットで、うまく使えば3Dのゲーム・2Dのゲームに関わらず活躍できそうなアセットです。
個人的には、このアセットを使用する場合はまるっとこのアセットに身を任せてゲームを作るほうがより真価を発揮しそうかなと思います。
一部の機能だけ使おうとすると、ほかの使わない機能がたくさんついてくるイメージですね～。

この記事がどなたかの参考になれば幸いです！