導入
Unity Assets で公開されている Dialogue System などの会話システムでは独自のグリッドビューで実装されていることが多い。それを Visual Scripting で独自ユニットを作って実装したい。
必要となるユニットは「メッセージを送り返事がくるまで待機するユニット」、「メッセージが送られてくるのを待つユニット」と「送られてきたメッセージに返事をするユニット」の3つ。
ListnerUnit (メッセージが送られてくるのを待つ)
public class ListenerUnit : Unit {
[DoNotSerialize] ControlOutput Exit;
[DoNotSerialize] ValueOutput Message;
protected override void Definition() {
Exit = ControlOutput(nameof(Exit));
Message = ValueOutput<string>(nameof(Message));
}
public override void Instantiate(GraphReference instance) {
EventBus.Register<string>(new EventHook("CALL"), message => {
var flow = Flow.New(instance);
flow.SetValue(Message, message);
flow.StartCoroutine(Exit);
});
base.Instantiate(instance);
}
}
まずは、メッセージが送られてくるのを待つユニット。インスタンス作成時に EventBus
にイベントリスナーを登録する。EventBus
は Visual Scripting に標準で含まれる Custom Event ユニットでも内部で使用していて String
や GameObject
をキーとして登録できる。イベントを受け取ったら新しい Flow
を作成して起動する。
CallbackUnit(送られてきたメッセージに返事をする)
public class CallbackUnit : Unit {
[DoNotSerialize] ControlInput Enter;
protected override void Definition() {
Enter = ControlInputCoroutine(nameof(Enter), EnterCoroutine);
}
IEnumerator EnterCoroutine(Flow flow) {
EventBus.Trigger(new EventHook("CALLBACK"), "Callback!");
yield break;
}
}
次に、送られてきたメッセージに返事をするユニット。EventBus
でイベントを発火して終了する。
MessageUnit(メッセージを送り返事がくるまで待機する)
public class MessageUnit : Unit {
[DoNotSerialize] ControlInput Enter;
[DoNotSerialize] ControlOutput Exit;
[DoNotSerialize] ValueOutput Message;
protected override void Definition() {
Enter = ControlInputCoroutine(nameof(Enter), EnterCoroutine);
Exit = ControlOutput(nameof(Exit));
Message = ValueOutput<string>(nameof(Message));
}
IEnumerator EnterCoroutine(Flow flow) {
var replyed = false;
System.Action<string> callback = message => {
flow.SetValue(Message, message);
replyed = true;
};
EventBus.Register(new EventHook("CALLBACK"), callback);
EventBus.Trigger(new EventHook("CALL"), "Hello world!");
yield return new WaitUntil(() => replyed); // 返事を待機
EventBus.Unregister(new EventHook("CALLBACK"), callback);
yield return Exit;
}
}
最後に、メッセージを送り返事がくるまで待機するユニット。EventBus
に一時的にイベントリスナーを登録する。メッセージを引数として EventBus
を発火する。返事が返ってくるまで待ってイベントリスナーを登録解除して Flow
を進める。
スクリプトグラフ
作成したユニットを使ってグラフを作成する。メッセージを送る側と受け取る側で完全に2ラインに分けることができる。
テスト
[22:56:39] Click!
[22:56:41] Hello world!
[22:56:43] Callback!
出力結果は上記。秒数を開けて期待した順にログが出力できた。
さいごに
実際には上のラインにはメッセージを表示する前準備、表示、ユーザーのクリックを待機といった処理を挟み。下のラインでは Visual Scripting の多様なユニットと組み合わせて会話の流れをノードで表現できるようになる。EventBus
さえ仕込んでしまえばいいので、上のラインは MonoBehavior
側に任せて、会話だけノードベースで管理することもできる。詳細な実装にはパッケージ内の EventUnit.cs
のソースコードを参考にされたい。