【Unity】PlayerSettingのPreloadedAssetsでメモリに常駐するファイルをシンプルに管理する

UnityのPreloadedAssetsでメモリに常駐するファイルをシンプルに管理する方法です。

Unity2020.1.10

PreloadedAssets?

PreloadedAssetsは登録しておいたアセットをプレイヤーの起動時に自動的に読み込む機能です。
読み込まれたアセットはメモリに常駐するため簡単にアクセスできます。

何らかの初期化に必要な設定ファイルなど、サイズが小さくて起動時に読んでおきたいアセットを管理するのに便利です。

PreloadedAssetsの使い方

PreloadedAssetsは以下のように、PlayerSettings.GetPreloadedAssets()で取得してPlayerSettings.SetPreloadedAssets()で上書きします。

// 現在のPreloadedAssetsに登録されているアセットをすべて取得
var preloadedAssets = PlayerSettings.GetPreloadedAssets().ToList();

// 何か足す
preloadedAssets.Add(instance);

// 上書き
PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());

こうして登録したアセットは起動時(エディタだったら再生時)に自動的に読み込まれるので、
例えば以下のようにシングルトンなScriptableObjectを通してアクセスします。

using UnityEngine;

public class Example : ScriptableObject
{
    public static Example Instance { get; private set; }

    private void OnEnable()
    {
        Instance = this;
    }
}

使用例

最後に使用例として、ScriptableObjectを設定ファイルとして使用する例を掲載します。

using System;
using System.IO;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;

public class FooConfig : ScriptableObject
{
    private static FooConfig _instance;
    
    public static FooConfig Instance
    {
        get
        {
#if UNITY_EDITOR
            if (_instance == null)
            {
                var asset = PlayerSettings.GetPreloadedAssets().OfType<FooConfig>().FirstOrDefault();
                _instance = asset != null ? asset : CreateDefault();
            }

            return _instance;

#else
            if (_instance == null)
            {
                // PreloadedAssetsに登録されていなかったらデフォルトのインスタンスを返す
                _instance = CreateInstance<FooConfig>();
            }

            return _instance;
#endif
        }
        private set => _instance = value;
    }

    private void OnEnable()
    {
        _instance = this;
    }

#if UNITY_EDITOR
    [MenuItem("Assets/Create/FooConfig")]
    private static void Create()
    {
        // 既に存在していたらエラー
        var asset = PlayerSettings.GetPreloadedAssets().OfType<FooConfig>().FirstOrDefault();
        if (asset != null)
        {
            throw new InvalidOperationException($"{nameof(FooConfig)} already exists in preloaded assets");
        }

        var assetPath = EditorUtility.SaveFilePanelInProject($"Save {nameof(FooConfig)}", nameof(FooConfig),
            "asset", "", "Assets");

        if (string.IsNullOrEmpty(assetPath))
        {
            // キャンセルボタン押下
            return;
        }

        // フォルダがなかったら作る
        var folderPath = Path.GetDirectoryName(assetPath);
        if (!string.IsNullOrEmpty(folderPath) && !Directory.Exists(folderPath))
        {
            Directory.CreateDirectory(folderPath);
        }

        // アセットを作成してPreloadedAssetsに設定
        var instance = CreateInstance<FooConfig>();
        AssetDatabase.CreateAsset(instance, assetPath);
        var preloadedAssets = PlayerSettings.GetPreloadedAssets().ToList();
        preloadedAssets.Add(instance);
        PlayerSettings.SetPreloadedAssets(preloadedAssets.ToArray());
        AssetDatabase.SaveAssets();
    }
#endif
}

参考

docs.unity3d.com

docs.unity3d.com