LoginSignup
1
1

[Unity Visual Scriptng] Dialogue System のベースとなる待機可能なユニットをコルーチンで作る

Last updated at Posted at 2023-07-18

導入

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 ユニットでも内部で使用していて StringGameObject をキーとして登録できる。イベントを受け取ったら新しい 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ラインに分けることができる。
stepexecutegraph.jpg

テスト

[22:56:39] Click!
[22:56:41] Hello world!
[22:56:43] Callback!

出力結果は上記。秒数を開けて期待した順にログが出力できた。

さいごに

実際には上のラインにはメッセージを表示する前準備、表示、ユーザーのクリックを待機といった処理を挟み。下のラインでは Visual Scripting の多様なユニットと組み合わせて会話の流れをノードで表現できるようになる。EventBus さえ仕込んでしまえばいいので、上のラインは MonoBehavior 側に任せて、会話だけノードベースで管理することもできる。詳細な実装にはパッケージ内の EventUnit.cs のソースコードを参考にされたい。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1