会話シーンとして宴を使う


投稿日:2014年6月11日 | 最終更新日:2024年5月25日

宴はビジュアルノベルだけではなく、ゲームの会話シーンやチュートリアルとして使うこともできます。
その方法をまとめました。


既存のシーンに、シナリオ再生エンジンを追加

「Tools > Utage > New Project」から新規プロジェクトを作成します。


プロジェクト名を入力し、「Type」を「Add To Current Scene」に設定します。

LayerSettingで、既存シーンのレイヤーとは独立して宴用のレイヤーを設定する必要があります。デフォルトのUtage、UtageUIのままでも基本的には問題ありませんが、好きなレイヤー名を設定することも可能です。
GameScreenSizeで、作成するゲームが想定する画面サイズを設定します。スマートフォンなどでは、実際の機体の解像度はバラバラなのでこのサイズを基準に拡大縮小して表示します。

Createボタンを押して、既存のシーンにシナリオ再生に必要なGameObjectと、シナリオ用のエクセルやAssetが追加します。
ここまでで、準備は終わりです。

シナリオの書き方

基本

シナリオデータ上では、「*シナリオラベル」から「EndScenarioコマンド」が一区切りになります。
なので、会話シーンの区切りにEndScenarioを設定するようにしてください。

シナリオの記述例
2014-06-11_10h39_44
EndScenarioで、会話パートの区切りとしている。

宴の表示を残したままゲーム側と連動させる

EndScenarioを使った場合は、宴の全ての表示も終了してしまうので、キャラクター等が非表示になってしまいます。
表示を残したままにしたい場合は、PauseScenarioコマンドを使ってください。
チュートリアルの作成などで役立つと思います。

シナリオの記述例

ゲーム側から宴を呼び出す

会話シーンとして使う場合、シナリオは自動的に再生されることはありません。
それぞれのゲームに合わせて任意のタイミングでシナリオを呼び出すプログラムを書く必要があります。

AdvEngineでシナリオ呼出しで使う基本的な機能

主な機能は次の通りです。 機能 AdvEngineのメソッド、プロパティ
シナリオの呼び出し JumpScenario( string scenarioLabel)
シナリオが終了したか判定 IsEndScenario
シナリオがポーズしたか判定 IsPausingScenario
シナリオが終了もしくはポーズしたか判定 IsEndOrPauseScenario
PauseScenarioコマンドで一時停止させたシナリオを再開する ResumeScenario

AdvEngineを制御するサンプルコード

AdvEngineを直接参照して扱うよりも、以下のような制御用のコンポーネントを作って
それ経由で呼び出すほうが楽になると思います。
あくまでサンプルなので、これをもとに自分のプロジェクトに合わせて使いやすいように書き換えていってください。

using System;
using System.Collections;
using UnityEngine;
using Utage;
using UtageExtensions;

    public class SampleAdvEngineController : MonoBehaviour
    {
        // ADVエンジン
        public AdvEngine AdvEngine { get { return advEngine; } }
        [SerializeField]
        protected AdvEngine advEngine;

        //再生中かどうか
        public bool IsPlaying { get; private set; }

        float defaultSpeed = -1;

        //指定のラベルのシナリオを再生する
        public void JumpScenario(string label)
        {
            StartCoroutine(JumpScenarioAsync(label, null));
        }

        //指定のラベルのシナリオを再生する
        //終了した時にonCompleteが呼ばれる
        public void JumpScenario(string label, Action onComplete)
        {
            StartCoroutine(JumpScenarioAsync(label, onComplete));
        }

        IEnumerator JumpScenarioAsync(string label, Action onComplete)
        {
            IsPlaying = true;
            AdvEngine.JumpScenario(label);
            while (!AdvEngine.IsEndOrPauseScenario)
            {
                yield return null;
            }
            IsPlaying = false;
            if(onComplete !=null) onComplete();
        }

        //指定のラベルのシナリオを再生する
        //ラベルがなかった場合を想定
        public void JumpScenario(string label, Action onComplete, Action onFailed)
        {
            JumpScenario(label, null, onComplete, onFailed);
        }

        //指定のラベルのシナリオを再生する
        //ラベルがなかった場合を想定
        public void JumpScenario(string label, Action onStart, Action onComplete, Action onFailed)
        {
            if (string.IsNullOrEmpty(label))
            {
                if(onFailed!=null)onFailed();
                Debug.LogErrorFormat("シナリオラベルが空です");
                return;
            }
            if (label[0] == '*')
            {
                label = label.Substring(1);
            }
            if (AdvEngine.DataManager.FindScenarioData(label) == null)
            {
                if(onFailed!=null)onFailed();
                Debug.LogErrorFormat("{0}はまだロードされていないか、存在しないシナリオです", label);
                return;
            }

            if (onStart != null) onStart();
            JumpScenario(
                label,
                onComplete);
        }

        //シナリオの呼び出し以外に、
        //AdvEngineを操作する処理をまとめておくと、便利
        //何が必要かはプロジェクトによるので、場合によって増やしていく

        //以下、メッセージウィンドのテキスト表示速度を操作する処理のサンプル

        //メッセージウィンドのテキスト表示の速度を指定のスピードに
        public void ChangeMessageSpeed( float  speed)
        {
            if (defaultSpeed < 0 )
            {
                defaultSpeed = AdvEngine.Config.MessageSpeed;
            }
            AdvEngine.Config.MessageSpeed = speed;
        }
        //メッセージウィンドのテキスト表示の速度を元に戻す
        public void ResetMessageSpeed()
        {
            if (defaultSpeed >= 0)
            {
                AdvEngine.Config.MessageSpeed = defaultSpeed;
            }
        }
    }

サンプルコンポーネントを使った実装例

制御コンポーネントをシーン内の任意のオブジェクト(非アクティブだとエラーがでるのでアクティブなオブジェクト)にAddComponentして
捜査対象のAdvEngineオブジェクトをコンポーネントに設定してください。
この辺は一般的なUnityの使い方と同じです。
会話シーンで使っているということは、Unityの基本的なゲームの実装方法は把握していると思うので、この項目は不要かもしれませんが、
一応具体的にまとめておきます。

ボタンを押すと、会話シーンが表示されるようにする例


実際は、シナリオラベルをゲームの内容によって変えると思われるので、プログラムから呼び出すことになるでしょう。

会話シーンでよくあるカスタムパターン

基本的には、特に調整する必要なく会話シーンとしては使えると思いますが、場合によっては宴側の調整が必要です。
会話シーンで必要となりやすい宴の設定方法について、まとめました。

スマートフォンなどの画面サイズが変わるゲームに対応させる

こちらのドキュメントを参考にしてください
端末のスクリーン解像度に合わせてアスペクト比を可変にする

セーブ処理を無効化する

宴は本来はビジュアルノベルゲームのツールなので、それらのセーブ機能を持っています。
会話シーンとして使う場合は、それらが邪魔になることもあるので、その場合は次のように無効化してください。

AdvSaveManagerは、主に途中まで読んだシナリオをセーブして再開するための機能で、一般的にイメージされるノベルゲームのセーブデータを制御します。
会話シーンとして使う場合は、使用しないことがほとんどだと思うので無効化しておいてください。
ドキュメント:AdvSaveManager

AdvSystemSaveManagerは、システムセーブデータを制御しています。
メッセージ速度や音量などの設定的なものや、ParamシートでSystemタイプにしたパラメータがセーブされます。
場合によっては使用するかもしれませんが、不要な場合は無効化してください。
ドキュメント:AdvSystemSaveManager

文字送りや改ページなどのクリック判定について

デフォルトでは、宴のクリック判定は「一番奥」になるので、シーン内の他のUIに当たり判定があるとそちらへのクリックが優先されて、宴へのクリック判定はブロックされてしまいます。
クリックがうまく反応しない時などは、シーン内の背景などの当たり判定(RaycastTargetなど)をオフにするなどしてみてください。

一番奥ではなく特定のオブジェクトに反応させるなど、クリック判定のやり方を変える場合はこちらの手法をつかってみてください。
クリック検知をカスタム

コンフィグ設定でメッセージウィンドウの透明度が変わるの機能を解除する

デフォルトでは、メッセージウィンドウの透明度はコンフィグ画面でゲームのプレイヤーが変更できるようになっています。
会話シーンを使用する場合は、この機能が邪魔になることがあります。
無効化する場合は、各メッセージウィンドウのオブジェクトの「AdvUguiMessageWindow」コンポーネントの「translateMessageWindowRoot」を「None」にしてください。

複数シーンを使った実装

これに関しては、基本的には宴の使い方の話ではなく、Unityの使い方の話になります。
一応知る限りをまとめましたが、初心者にはかなりハードルが高いと思います。
Unityでの複数シーンを使ったゲームの実装方法とメモリリークについて
宴との組み合わせ方法に関しては、基本的には加算シーンを使い、さらに宴をマネージャーシーンとして常駐させることをお勧めします。
ただ、やはり根本的にはUnityの使い方の話になるので、疑問点がある場合はまずUnityに問い合わせるなどして、Unityの一般的な開発手法として解決してください。
宴のQ&Aに問い合わせるときは、「複数シーンを使うために、宴側に〇〇できるコールバックが欲しい」とか「複数シーンを使っていると、XXでリークしているので直してほしい」とか、具体的に宴を対象とした問い合わせをしてください。

シーン内のUIにシナリオ再生を埋め込む

宴の表示オブジェクトは、基本的にはAdvEngine以下に表示されます。
既存のUIオブジェクト以下に宴のシナリオで再生するキャラなどを表示する場合は、
シーン内のUIに宴のシナリオ再生を埋め込むを参考にしてください。