[実験室・備忘録]【UnityでNovelゲームのスケルトンみたいなものを作ってみたい】[番外]

 メインではLive2DCubismのキャラを読み込んでいましたが、番外として、ノベルエンジンに静止画を読み込む実験もしていたのでそれも備忘録として残しました。

【実験1】パネルの中に直接立ち絵スプライト(3人)配置したらソートはどうなるのか?

 [結果]スプライトレンダラーのソートでキャラの表示順は制御できても、テキストボックスは後ろにいってました。UIコンポーネントにぶら下がっていれば(Panelのimageにスプライトを割りつけるとか)、テキストボックスとのソート順も維持されるけど。単独ではやっぱりダメか。

Panelの中に直接スプライトを配置してみたけど

【実験2】複数の立ち絵キャラを配置した場合、シナリオによって、A、B、Cが入れ替わり経ち替わり、色んな表情で出たり入ったりする時のメモリ管理は?

 既存クラスを利用して、CharaCGという名前でPanelを作り、キャプチャーの様にヒエラルキービューに挟み込んでます。またPanelの中に、入れ子のPanel、CharaImagA、CharaImagB、CharaImagCを作り、目印とするためA、B、CのPanelの初期の大きさを100×100pxとしてColorを赤、緑、青と割りつけています。そして各Panelには、CharaCGManagerというBGManagerのコピーをImageManagerクラスの子クラスを紐づけました。

真ん中がA。右がB。左がC。

 参考サイトでは、非表示にする処理はあるけどもう使わないとか暫く使わないからメモリから追い出したい時のことは書いてなかったので、読み込みと追い出しについて調べて考えてみました。

 とりあえず調べて参考になりそうな記事がこれ。

▼画像のロード関係
 [sh1’s diary][Unity アセット管理 Addressables の基本的な考えと使い方]
Unity アセット管理 Addressables の基本的な考えと使い方 - sh1’s diary
Addressables の仕組み is なに? Addressables の使い方 テスト Event Viewer ロード/アンロードを可視化する 参考 画像などのアセットデータをプロジェクトに追加して利用する方法として、以下のような手...

 ImageManagerの、Addressables.LoadAssetsAsync(_LabelTest, null).Completed += sprites => あたりに関係してきます。更に、[ロード/アンロードを可視化する]という項目でViewerの出し方が説明されているので目を通しておきたい。
▼画像のメモリ管理
[[Unity] Resources.Loadの代わりにAddressable Asset Systemを使ってみる]
[Unity] Resources.Loadの代わりにAddressable Asset Systemを使ってみる - Qiita
はじめに Unityで動的にアセットを読み込む際、Resources.Loadの使用はベストプラクティスでないという話があります。 (ただし、Resources.Loadは手軽で便利という側面もあり、例えばゲームジャムやプロトタイプ...

 取得したスプライトを変数に保存して、スプライトレンダラーに割りつけている例が示されていたので、A、B、Cのメモリ管理を考える際の参考に。

 上記参考サイトを読んで、画像を管理するImageManager(親)クラスに新たに、画像ファイルパスから取得したスプライトを格納する _myspriteと、シナリオデータに記述したコマンドをキャラが判別できるような名前にして、例.) &charaA それをキーにして連想配列で管理し、リリース時にキーを使って目的の画像を削除し、Viewerで消えてゆくか確認できるようにする。というものを考えてみました。

[ImageManager.csへの追加・修正文]
▼宣言部
using UnityEngine.AddressableAssets; // リソース管理を簡単にやってくれるライブラリ
▼クラス内先頭
Sprite _mysprite = null; // 解放するときに取得したスプライトがないと困るので
// Dictionaryクラスの宣言と初期化
Dictionary img_dic = new Dictionary(); // キャラA~Cまでを格納する
▼executeCommandToOperateImage()内

public void executeCommandToOperateImage(string[] command)
{
    for(int i=1; i<command.Length; i++)
    {

        // ★省略(原文と同じ)

        switch(commandAttribute)
        {
            case "img":
                Addressables.LoadAssetAsync<Sprite>(commandValue).Completed += sprite =>
                {
                    _image = GetImage();    // ★各子クラスのGetImageが行われる
                    _image.color = new Color(_image.color.r, _image.color.g, _image.color.b, 1);   // アルファが100%
                    _image.type = Image.Type.Simple;
                    _mysprite = sprite.Result;  // 解放時の為取得したスプライトを保存

                    switch (command[0])
                    {
                        case "&charaA":
                            img_dic.Add("charaA", _mysprite);    // charaAというキー名で登録
                            break;
                        case "&charaB":
                            img_dic.Add("charaB", _mysprite);    // charaBというキー名で登録
                            break;
                        case "&charaC":
                            img_dic.Add("charaC", _mysprite);    // charaCというキー名で登録
                            break;
                    }

                    _image.sprite = _mysprite;  // ★クローンでは無く、ロード後のアドレスそのものを渡す

                    // 追加分(背景とかの大きさに悪影響でるなら場合分け必要)
                    _image.SetNativeSize();  // 割りつけた後に、元のサイズで表示するように指定
                };
                break;
            case "rm":
                _image.color = new Color(_image.color.r,_image.color.g,_image.color.b,0);   // アルファが0%なので透過
                break;
            /*
            case "rm_chara":
                // メモリからも削除する
                Debug.Log("rm_charaに入った");
                //Destroy(_image.sprite); // ★通りはする(キャラのスプライトは外れる)。だが、メモリは解放されない
                Addressables.Release(_mysprite);    // ★★保存しておいたスプライトを解放することでスタックから消える
                break;
            */
            case "rm_charaA":
                // メモリから削除する
                Debug.Log("rm_charaAに入った");
                _image.sprite = null;   // ヌルを指定して画面上のpanelのimageに紐づいているスプライトを外す
                 Addressables.Release(img_dic["charaA"]);    // ★charaAをメモリから削除
                // Dictionaryからも削除する
                img_dic.Remove("charaA");
                break;
            case "rm_charaB":
                // ★省略 case "rm_charaA":の内容をBに打ち換えたものが入ります
                break;
            case "rm_charaC":
                // ★省略 case "rm_charaA":の内容をCに打ち換えたものが入ります
                break;
        }
    }
}

 これが期待したように動いていると下のようなキャプチャーに。Viewerにロードされたり、リリースされたりしてる様子が観察出来ます。

 サンプルで配布しているような立ち絵を入れ替わり立ち替わり、入れ替えるのは理屈だけならこんな感じでもいいのかなぁ。
【メモ】サンプル画像は使う前に減量して軽くしておかないと(;´・ω・)

コメント

タイトルとURLをコピーしました