【Unity】Fungusを使ってセリフ機能を実装する

Unity
マイケル
マイケル
どうもみなさんこんにちは!
マイケルです!
エレキベア
エレキベア
こんにちはクマ〜〜〜
マイケル
マイケル
前回、オリジナルゲームを作成しているとの記事を書いたのですが、
その中でもセリフ機能の実装について今回は紹介します!

スクリーンショット 2020 05 09 14 16 20

エレキベア
エレキベア
このセリフの部分のことクマね
マイケル
マイケル
その通り!
Fungusというアセットを使って実装しているんだ
マイケル
マイケル
今回はFungusを使った実装方法について解説するよ!
スポンサーリンク

Fungusの導入方法

マイケル
マイケル
導入はAssetStoreで「Fungus」を検索してインポートすれば完了です。
スクリーンショット 2020 05 10 0 08 28
エレキベア
エレキベア
簡単クマ〜〜〜

Fungusを使った実装方法

マイケル
マイケル
導入が完了したら以下の手順で会話機能を作成していきます。


1. Flowchartの作成
2. Characterオブジェクトの作成
3. メッセージの作成

Flowchartの作成

マイケル
マイケル
会話の内容はフローチャートで作成していくのですが、そのためにFlowchartスクリプトを持つオブジェクトが最低一つは必要になります。
マイケル
マイケル
Tools -> Fungus -> Create -> Flowchart
より、オブジェクトを作成しましょう。
スクリーンショット 2020 05 10 0 35 22
エレキベア
エレキベア
きのこマークがついてかわいいクマ

Characterオブジェクトの作成

マイケル
マイケル
次に、会話させるキャラクターのオブジェクトを作成します。
Flowchartと同じく
Tools -> Fungus -> Create -> Character
から作成しましょう!
スクリーンショット 2020 05 10 0 38 22
マイケル
マイケル
キャラクターオブジェクトには、名前とキャラクターの画像を設定します。

メッセージの作成

マイケル
マイケル
ここまでで準備は完了で、あとはメッセージを作っていきます。

・ゲーム開始時の出力

マイケル
マイケル
まずは手始めにゲーム開始時のセリフを作成してみましょう!
Tools -> Fungus -> Flowchart Window
を選択するとフローチャートのウィンドウが開きます
マイケル
マイケル
ブロックにはそれぞれ誰が何のセリフをいうか、等の情報を記述していきます
ブロックは右クリック -> AddBrockから追加できます。
スクリーンショット 2020 05 10 0 43 54
エレキベア
エレキベア
セリフの呼び出しや選択パターンをここで分けるクマね
マイケル
マイケル
その通りだよ
ブロック内のExecute On Eventには呼び出されるタイミングを設定し、
初期値の「Game Started」はゲーム開始時の出力処理になります。
マイケル
マイケル
Commands欄にはSayコマンドでセリフを設定して、Callコマンドで呼びだすブロックを指定して会話の流れを作るのが基本となります!
マイケル
マイケル
上記のように設定した状態でゲームをスタートするとセリフが出てきます。
スクリーンショット 2020 05 09 14 16 20
エレキベア
エレキベア
ゲームっぽいクマ〜〜〜!!
マイケル
マイケル
セリフのUIも黒でおしゃれでいいよね

・キャラクターに話しかけた時

マイケル
マイケル
次に自分で指定したタイミングで呼び出したい場合の設定方法です!
ここでは例としてキャラクターに話しかけた時の設定とします
マイケル
マイケル
フローチャート上はExecute On Event にMessage Receiveを指定し、メッセージに任意の値を設定してください。
スクリプトからの呼び出しでメッセージの値を指定することで呼び出すことができるようになります!
スクリーンショット 2020 05 10 1 32 32
マイケル
マイケル
スクリプト側の設定としては、まずキャラクターの会話範囲を指定するためコライダを設定し、そこにスクリプトを作成してアタッチします。
(下記では、「TalkArea」の箇所になります)
スクリーンショット 2020 05 10 1 35 00
public class TalkArea : MonoBehaviour
{
    // ********************
    // * 変数定義          *
    // ********************

    /** コンポーネント */
    InputManager inputManager;
    FriendCtrl friendCtrl;

    /** 設定値 */
    public string messageId; // メッセージID

    /** 変数 */
    // 会話情報
    public class TalkInfo
    {
        public Transform talkTarget;  // 会話対称 
        public string messageId;      // メッセージID
    }

    // ********************
    // * 処理実行          *
    // ********************

    void Start()
    {
        inputManager = FindObjectOfType<InputManager>();
    }

    private void OnTriggerStay(Collider other)
    {
        // 衝突対称がプレイヤーかつ会話キーが押された場合
        if (other.tag == GameUtil.Const.TAG_PLAYER && inputManager.GetTalkKey())
        {
            // プレイヤーの会話対称を設定
            other.SendMessage("SetTalkInfo", GetTalkInfo(null));
        }
    }

    TalkInfo GetTalkInfo(Collider player)
    {
        TalkInfo talkInfo = new TalkInfo();
        talkInfo.talkTarget = transform;
        talkInfo.messageId = messageId;
        return talkInfo;
    }
}
マイケル
マイケル
会話範囲にプレイヤーが入っている時にボタンが押されるとプレイヤーのスクリプトの処理を呼び出すようにしています。
プレイヤー側のスクリプト処理は以下の様に記述しています。
    /** 変数 */
    Transform talkTarget;   // 会話対象の位置
    string talkMessageId;   // メッセージID

    // ステート
    enum State
    {
        Walking, // 移動
        Talking, // ジャンプ
    };
    State state = State.Walking;     // 現在のステート
    State nextState = State.Walking; //次のステート
    
・・・略・・・

    void Update()
    {
        // ステートに応じた処理
        switch (state)
        {
            case State.Walking:
                Walking();
                break;
            case State.Talking:
                Talking();
                break;
        }
        // ステート遷移処理
        if (state != nextState)
        {
            state = nextState;
            switch (state)
            {
                case State.Walking:
                    WalkStart();
                    break;
                case State.Talking:
                    TalkStart();
                    break;
            }
        }
    }

・・・略・・・

    void Walking()
    {
・・・略・・・
        // 会話対称が設定されている場合、会話処理を行う
        if (talkTarget)
            ChangeState(State.Talking);
・・・略・・・
      }
    
    // --------------- 会話 ---------------

    // 会話情報を設定する
    public void SetTalkInfo(TalkArea.TalkInfo talkInfo)
    {
        talkTarget = talkInfo.talkTarget;
        talkMessageId = talkInfo.messageId;
    }

    // 会話Start
    void TalkStart()
    {
・・・略・・・

        // 会話処理開始
        flowchart.SendFungusMessage(talkMessageId);
    }
マイケル
マイケル
トリガーからの呼び出しで会話情報が設定された後、TalkStart()の部分でメッセージの呼び出しを行なっています。
flowchart.SendFungusMessage()にメッセージを渡すことで呼び出すことができます。
エレキベア
エレキベア
これで会話ができる様になったクマ!
マイケル
マイケル
一旦できるようになったね
でも、この状態だと会話している最中に他の処理が行われてしまうことがもありえるため、
もう一歩、会話中の状態を取得して判定できるようにしていきます!
マイケル
マイケル
フローチャート上で、下記の様に会話の始めと終わりでboolean型の変数を変更する様にします。
変数は、フローチャート左下の+マークから追加できます!
スクリーンショット 2020 05 10 1 57 25
スクリーンショット 2020 05 10 1 57 34
マイケル
マイケル
こうすることで追加したboolean型の変数で会話中かどうかを判定できるようになりました。
スクリプトを下記の様に修正します。
・・・略・・・

    private void OnTriggerStay(Collider other)
    {
        // 会話中なら処理終了
        if (!flowchart.GetVariable<BooleanVariable>("Talking").Value)
            return;

        // 衝突対称がプレイヤーかつ会話キーが押された場合
        if (other.tag == GameUtil.Const.TAG_PLAYER && inputManager.GetTalkKey())
        {
            // プレイヤーの会話対称を設定
            other.SendMessage("SetTalkInfo", GetTalkInfo(null));
            // NPCの会話対称を設定
            friendCtrl.SetTalkInfo(GetTalkInfo(other));
        }
    }

・・・略・・・
    /** 変数 */
    Transform talkTarget;   // 会話対象の位置
    string talkMessageId;   // メッセージID
    FriendCtrl talkFriend;  // 会話対象

・・・略・・・
    
    // --------------- 会話 ---------------

    // 会話情報を設定する
    public void SetTalkInfo(TalkArea.TalkInfo talkInfo)
    {
        talkTarget = talkInfo.talkTarget;
        talkMessageId = talkInfo.messageId;
        talkFriend = talkInfo.friendCtrl;
    }

    // 会話Start
    void TalkStart()
    {
・・・略・・・

        // 会話処理開始
        flowchart.SendFungusMessage(talkMessageId);
    }

    // 会話Update
    void Talking()
    {
        // 会話終了時
        if (!flowchart.GetVariable<BooleanVariable>("Talking").Value)
        {
            // 会話対象の終了処理呼び出し
            talkFriend.SendMessage("TalkEnd");
            // 初期化
            talkTarget = null;
            talkMessageId = null;
            talkFriend = null;
            // 移動処理に遷移
            ChangeState(State.Running);
        }
    }
・・・略・・・
    /** 変数 */
    Transform talkTarget;   // 会話対象の位置
    bool talkEnd;           // 会話終了判定

・・・略・・・

    // --------------- 会話 ---------------

    // 会話情報を設定する
    // (TalkAreaより呼び出される)
    public void SetTalkInfo(TalkArea.TalkInfo talkInfo)
    {
        talkTarget = talkInfo.talkTarget;
    }

    // 会話終了処理
    // (PlayerCtrlより呼び出される)
    public void TalkEnd()
    {
        talkEnd = true;
    }

・・・略・・・

    // 会話Update
    void Talking()
    {
        // 会話終了後、移動処理に遷移
        if (talkEnd)
        {
            talkTarget = null;
            ChangeState(State.Walking);
        }
    }
マイケル
マイケル
上記のようにFlowchartで設定した変数を取得することで、会話中は処理を行わないなど判定を入れることができます!
これで会話の処理は完成です!
画面収録 2020 05 09 18 35 12
エレキベア
エレキベア
いい感じに会話できてるクマ〜〜〜!!

おわりに

マイケル
マイケル
会話機能アセットFungusの使い方を見ていきましたが、いかがだったでしょうか。
エレキベア
エレキベア
ゲームっぽくなって楽しかったクマ〜〜〜〜
マイケル
マイケル
Fungusには上記で紹介した処理以外にも機能がありますし、会話のアセット自体もFungus以外にたくさんあります。
是非他の機能も調べてみてください!
マイケル
マイケル
それでは今回はこの辺で!
アデュー!!

【Unity】Fungusを使ってセリフ機能を実装する 〜完〜

コメント