もっきゃりぺお 2023/12/07 22:06

【ノベルゲーム制作】④Unity Naninovel カスタムUI、カスタム変数【まほだん】

Unityのことを完全に理解した

完全に過言ですが、ちょっとずつこなれてきている感じがします。またまた時間が開いてしまいましたが、進捗がないというよりは、機能を色々と追加していて、せっかく動画にするならちょっとまとまったところまでやろう、という感じで溜め込んでいました。AC6ももりもりやりましたが。

というわけで、何はともあれまず成果物です。

見ての通り、画面が動いたり、タイマーが表示されたり、カーソルが切り替わったりしてます。あと、Naninovelのバージョンがv1.18とそれ以前で大きく変わっていて、特に、TextからText Mesh Proに変わったこととかもあります。全部一つの記事にまとめると大変なので、いくつかに記事を分けます。

Naninovelというか、Unityをやっててわかったのは、まあオブジェクト指向なんですね。そりゃそうなんですけど、いや、今更って話なんですけど、なんか作りながらわかっていけばいいか~という気持ちで触れてたので、なんというかそういうことが腑に落ちたという感じです。インスペクターでぽちぽちしてるけど、基本的にはとりあえず、UnityEventを使って、呼び出す関数と、関数を呼び出す仕組みを作ればまあ色々できるというのを、GUIで便利にしてるんだな、というのがわかってきました。それを使って、タイマーを作ったり、アニメーションに合わせてSEを入れたり、カーソルを変えたりというのを作ってます。

それと、ラジオは一応毎月かかさずとってるので、有料のプランの方は聴いてみてね。

特別な演出

目的 ―― Naninovelにない演出や特別な処理をしたい

Naninovelにもいろんな効果や表現がデフォルトで実装されてますし、それだけでそれなりにリッチな表現ができると思うんですが、基本的にプレーンで、特定のスタイルを押し出したものではないし、冒頭の動画のようなタイマーみたいな処理は用意されていません。しかしNaninovelはUnityのアセットなので、プログラムすればそれこそUnityで出来ることは何でもできると言ってもいいでしょう。

魔法少女確殺弾では、タイトルの通り魔法少女確殺弾で、それを撃つ、撃たないというのが重要な選択になっていきます。その重要な選択を強調するのに、特別な演出を実装することになりました。
まほだん制作開始時ではそんな予定ではなかったんですが、専用のUIをこんな感じでやるといいんじゃないか、とみるきさんと話し合って、やることになりました。

カスタムUI ―― NaninovelとUnityの自由さの接合面

Naninovelでそういう色々な機能を追加したいときには、カスタムUIというものを使います。

WARNING
カスタムUIを作成したり、既存のUIを変更したりする前に、まずUnityのUIシステム 🡕(uGUI)をよく確認してください。以下で利用できるUIカスタマイズのチュートリアル動画とサンプルプロジェクトがありますが、Unityの組み込みツールについて追加のガイダンスまたはサポートは提供していませんので、ご注意してください。詳細は サポートページ をご覧ください。

って書いてありますが、Unityで好きにあれこれやるための機能なので、これを使えばかなりのことがNaninovelと結合できるよ、ということです。他のノベルゲームのエンジンについて何も詳しくないのであれなんですけど、UnityのPrefabやAnimatorの表現力や自由度ってかなりのものだと思っていて、わざわざUnity使ってノベルゲーム作る人って、そのあたりに魅力を感じているからではないでしょうか。たぶん。

カスタムUIの機能を使うと、動画の、黒い枠がにゅーっと出てきたり、タイマーを呼び出したりとか、カーソルが変わったりの演出が、


こんなかんじに、
@showUI MahodanUI (枠がでるほう) @showUI TimerUI (タイマーのほう)
とか
@hideUI TimerUI @hideUI MahodanUI
とかのコマンドで出し入れできるようになります。
Naninovel公式の説明動画だと、コマンドでカレンダーを呼び出してるのがわかりますね。私はだいたいこの動画を真似して実装していきました。

カスタムUIの作り方 ―― 無垢なカスタムUIの赤ちゃん

カスタムUIを作って使えるようにするだけなら、かなり簡単にできるようになっています。といっても、それだけだと何も機能のないものになりますが。


こんなかんじで、Projectの中を右クリックして、Create→Naninovel→CustomUIをすると、NewCustomUIというPrefabが作成されます。このカスタムUIの赤ちゃんに名前をつけて、Configulation→Naninovel→UIから登録すれば、それだけでオッケーです。

こんなかんじでMahodanUIとTimerUIが登録されてます。

カスタムUI ―― かわいいベイビーが動いたり、数を数えるようにする

Prefabを呼び出せるので、それだけで好きなオブジェクトを追加できて、枠なりなんなりはいくらでも作れます。枠や画像を出すだけじゃなくて、Prefabなのでアニメーションを入れたりもしてます。にゅーっと黒い枠で狭まる効果は、MahodanUIが呼び出されると共にアニメーションさせています。


これは実装したMahodanUIのCustomUIというコンポーネントです。項目は色々ありますが、重要なのはOn Show()とOn Hide()で、その通り、NaninovelからShowしたときとHideしたときにイベントを呼び出せるので、これによってアニメーションを操作してます。このあたりの処理は口パクのほうで結構書いたので、参考になれば。

Timerはこんな感じで、自作のscriptを追加しました。
ちょっと試行錯誤したままのコードなので恥ずかしいのですが、こんな感じです。

using UnityEngine;
using System.Collections;
using TMPro;
using Naninovel;
using UnityEngine.Events;

public class Timer : MonoBehaviour
{
    private float totalTime;
    private float seconds; // 秒数の変数
    private float timeSpeed = 1f; // timeSpeed の初期値を設定
    private bool timerStarted = false; // タイマーが開始されたかどうか

    [SerializeField]
    private TextMeshProUGUI TimerText;
     // 3秒以下の時に呼び出す
    [SerializeField]
    private UnityEvent onThreeSecondsLeftEvent;
     // 1秒以下の時に呼び出す
    [SerializeField]
    private UnityEvent onOneSecondLeftEvent;
    // タイマー終了時に呼び出す
    [SerializeField]
    private UnityEvent onTimerFinishedEvent;  

    public void Start()
    {
        
        timerStarted = false;

        // 外部の変数マネージャーから秒数を取得し、floatに変換して代入
        var variableManager = Engine.GetService<ICustomVariableManager>();
        string timerString = variableManager.GetVariableValue("timer");
        if (float.TryParse(timerString, out float timerValue))
        {
            totalTime = timerValue;
        }
        else
        {
            totalTime = 0f; // または適切なデフォルト値を設定
        }

        // タイマー表示用UIテキストを更新
        UpdateTimerText();
        StartCoroutine(UpdateTimerColor()); 
    }

    public void StartTimer() 
    {
        timerStarted = true; 
    }

    private void UpdateTimerText()
    {
        TimerText.text = totalTime.ToString("F2"); 
    }

    private IEnumerator UpdateTimerColor()
    {
        while (totalTime > 0f)
        {
            if (totalTime <= 1f)
            {
                TimerText.color = Color.red;
                onOneSecondLeftEvent.Invoke();
                timeSpeed = 0.8f; 
            }
            else if (totalTime <= 3f)
            {
                TimerText.color = Color.yellow;
                onThreeSecondsLeftEvent.Invoke();
                timeSpeed = 0.9f;
            }
            else
            {
                TimerText.color = Color.white; 
                timeSpeed = 1f;

            }

            yield return null; // 次のフレームまで待機
        }

        // タイマー終了時に timeSpeed を元に戻す
        timeSpeed = 1f;
    }

    void Update()
    {
        if (!timerStarted || totalTime <= 0f)
        {
            return;
        }

        totalTime -= Time.deltaTime * timeSpeed;

        if (totalTime < 0f)
        {
            totalTime = 0f;
        }

        // タイマー表示用UIテキストを更新
        UpdateTimerText();

        if (totalTime <= 0f)
        {
            Debug.Log("制限時間終了");
            onTimerFinishedEvent.Invoke(); 
        }
    }
}

こんなふうに自分で作った関数を呼び出せるので、カスタムUIでかなりのことができるなと思いました。同じ感じでカーソルが拳銃の照準に変わるのとかも、実装してます。
あとは、animatorの方にEventhandlerを持たせて、アニメーションに合わせてSEを鳴らしたりとかも実装しました。

カスタム変数 ―― Naninovelの方から変数に触る

ここで、タイマーの時間設定なんですが、8秒に設定されています。この決定は、自作のスクリプトの方ではなく、Naninovelの方で設定できるようになっています。Naninovelにはカスタム変数という機能があって、Naninovelのスクリプトの方からある程度変数に触れるようになっています。
公式のカスタムUIの日付表示の動画サンプルも、カスタム変数で実装しているので、この動画を見るとわかりやすいです。
タイマーの時間セットは、
@set timer=8 @showUI TimerUI @wait {timer+2}
という形でNaninovelのスクリプトの方で動くようになっています。
このtimerというカスタム変数を登録するだけなら、


こんなかんじでマニュアル通り、Custom Variablesに項目を追加するだけでできます。ここで作ったTimerというカスタム変数は、上記のコードだとstart()内の
var variableManager = Engine.GetService<ICustomVariableManager>(); string timerString = variableManager.GetVariableValue("timer");
で呼び出しており、設定したカスタム変数名を入れるだけで呼び出せます。

というわけで、今回はカスタムUIとカスタム変数について触れました。UnityそのものやC#についてはもっと詳しい記事がいっぱいあると思うので、そのあたりについてはかなり省略しました。

ゲームの制作って地道ですね。一つ一つ機能を追加したり、パラメータを調整したりして、いい感じになるように頑張っています。それでは!

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

月別アーカイブ

記事を検索