【Unity勉強記】AssetBundle


ABパッケージとは何ですか?

AssetBundle は、リソースを保存するために Unity によって提供される圧縮コレクションであり、モデル、テクスチャ、オーディオ、シーン、その他のリソースなど、Unity が認識できるあらゆるリソースを保存できます。開発者定義のバイナリもロードできます。

AB パッケージを使用する理由

リソースがパッケージ化されると、すべてのリソースが Resources にパッケージ化されます。つまり、一部のリソースだけが必要な場合でも、すべてのリソースをパッケージ化して削除する必要があり、読み取り専用であるため、任意に変更することはできません。パッケージの内容。

これに対し、AB パッケージを使用すると、さまざまなリソースを独立したパッケージにパッケージ化でき、AB パッケージの保存パスや圧縮方法をカスタマイズでき、パッケージ化されたコンテンツを後から動的に更新することもできます。

AB パッケージはパッケージのリソース サイズを節約できます。一方で、AB パッケージでは、圧縮時に優れた圧縮方法が可能であり、選択された圧縮リソースも自由に選択できます。一方、ゲームクライアントでは、AB パッケージが変更可能であるため、初期インストールのサイズを小さくすることができ、ゲームをインストールするときに、より小さな AB パッケージを設定してゲームを実行することができます。その後、AB パッケージの残りのコンテンツをダウンロードできます。

AB パッケージを使用すると、ホット アップデートの実行も容易になります。たとえば、King of Kings をプレイするときに、アップデートをダウンロードしませんでしたが、ゲーム インターフェイスは更新されました。これは、ゲーム内でダウンロードした AB パッケージ リソースをホット アップデートすることで実現できます。ゲームを更新してダウンロードする必要がある場合、クライアントは通常、最初にサーバーと通信してリソース サーバーのアドレスを取得し、それをリソース サーバーの AB パッケージと比較して、更新する必要があるリソースを決定します。


ABパッケージのエクスポート方法

AB パッケージ サービスをインストールした後、AB パッケージをエクスポートするにはどうすればよいですか?

1. オブジェクトを選択し、インスペクター インターフェイスの下部にバインドされたパッケージ名を入力 (選択) します。
2. [AssetBundles] パネルでパッケージ化されたパッケージを表示します。
3. エクスポート オプションを選択します

エクスポートオプションは次のとおりです

属性 オプション
ビルドターゲット オプションはエクスポートされたプラットフォームに対応します
出力 エクスポート パス、AB パッケージ ルート パス AssetBundles はアセットと同じレベルにあります
クリアフォルダー エクスポートフォルダーをクリアする
StreamingAssets にコピー エクスポートが完了したら、エクスポートされた AB パッケージを Assets フォルダーの StreamingAssets にコピーします。

さらに重要なパラメータ

属性 オプション
圧縮 圧縮モード: 圧縮なし 圧縮なし、解凍の必要なし、読み込みが速いという利点がありますが、ファイルが大きくなります
LZMA標準圧縮で圧縮率は高いが解凍が面倒
LZ4 ブロック圧縮。パッケージ内のリソースを使用する場合、対応するチャンクのみが解凍されます。メモリ使用量が少ないため、強くお勧めします。
型情報を除外する リソースタイプ情報は含まれません
強制再構築 パッケージ内のすべてのコンテンツの強制リファクタリング
タイプツリーの変更を無視する インクリメンタル ビルド チェックを実行するときにタイプ ツリーの変更を無視する
ハッシュの追加 アセットバンドル名に付加されたハッシュ (ハッシュ アドレッシング、ファイル検証)
ストリクトモード この間にエラーが報告されると、ビルドは失敗します。
ドライランビルド ドライランビルドを実行します。このオプションを使用すると、実際にアセットバンドルをビルドせずに、アセットバンドルに対してドライラン ビルドを実行できます。このオプションが有効な場合でも、BuildPipeline.BuildAssetBundles は有効な AssetBundle 依存関係とハッシュを含む AssetBundleManifest オブジェクトを返します。

さらに、Unity では C# を AB パッケージにパッケージ化できないため、Lua を学ぶ必要があります (笑、とても面白い)。AB パッケージにパッケージ化すると、オブジェクトの C# スクリプトには実際には FileID に対応するマッピングのみが含まれます。

4. Inspect で対応するリソースを開いて、エクスポートされた AB パッケージ内の情報を確認します。

さらに、シェーダやスプライトなどのパッケージ化されたオブジェクトによって使用されるリソースは、アクティブにパッケージ化されていなくても、自動的にパッケージ化されます (デフォルトでは、それらを使用するオブジェクトと同じパッケージ本体にパッケージ化されます)。この時点で、AssetLabel でどのパッケージに属するかを選択できます。ただし、オブジェクトが依存するリソースが他のパッケージに含まれている場合、オブジェクトを単独でロードすると他の依存リソースが失われることがよくあるため、このオブジェクトをロードするときは、その依存パッケージもロードする必要があることに注意してください。同時に。

ABパッケージエクスポートファイル

ここに画像の説明を挿入します

パッケージ化が完了すると、各パッケージはパッケージと対応するマニフェスト リストを生成します。さらに、メインパッケージと呼ばれるフォルダーと同じ名前のパッケージがあり、パッケージ間の依存関係に関する情報が保存されますすべてのパッケージには接尾辞がなく、バイナリ ファイルです。マニフェストにはリソースからの情報が含まれています。

コード内での呼び出しの利便性を考慮して、通常は以下を使用して StreamingAssets を確認することがよくあります。

Application.streamingAssetsPath + "/" +"包名"

AB パッケージのパスを読み取るには


ABパッケージの使い方

AB パッケージをロードしています

AB パッケージのロードは 2 つのステップに分かれており、最初のステップでは最初に AB パッケージをロードし、2 番目のステップではパッケージ内の対応するリソースをロードします。

同期ロード

最も簡単な方法は、AB パッケージのリソースを同期的にロードし、すべてのコードが順番に実行されることです。

まずABパッケージをロードします

AssetBundle AB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "包名");

リソースをロードするには 2 つの方法があり、1 つはジェネリックを使用してロードする方法、もう 1 つはタイプを指定して直接ロードする方法です。

// T对应加载的资源的类型
T obj = AB.LoadAsset<T>("包内资源名");
// T对应加载的资源的类型
T obj = AB.LoadAsset("包内资源名", typeof(T)) as T;

実用的な観点からは、最初の読み込み方法が適していますが、Lua はジェネリックスをサポートしていないため、実用的な観点からは 2 番目の方法の方が優れています。


この場合

非同期読み込み

Unity はシングルスレッドであり、同期ロード中に大量のリソースが発生してメイン スレッドがブロックされ、ゲームがフリーズすることは望ましくないため、非同期ロードが推奨される方法です。非同期ロードに関して言えば、間違いなく最初に思い浮かぶのはコルーチンです。コルーチンを使用してロードすることに加えて、AB パッケージはいくつかの非同期ロード メソッドも提供します。

    IEnumerator LoadABres(string ABName, string resName)
    {
    
    
        AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + ABName);
        yield return abcr;
        AssetBundleRequest abq = abcr.assetBundle.LoadAssetAsync(resName, typeof(Sprite));
        yield return abq;
        // 以加载Image组件的Sprite为例
        Sprite.sprite = abq.asset as Sprite;
    }

AB パッケージのアンインストール

AssetBundle.UnloadAllAssetBundles(true);
AssetBundle.UnloadAllAssetBundles(false);

UnloadAllAssetBundles メソッドは、2 つのモードを含め、ワンクリックですべての AB パッケージをアンインストールできます。True モードでは、シーン内の AB パッケージが直接アンインストールされ、シーンのリソースが失われます。false の場合、すべての AB パッケージがアンインストールされ、シーン リソースは失われません。

同様に、Unload メソッドを使用して、指定された AB パッケージをアンインストールできます (true と false は同じ)。

AB.Unload(true);
AB.Unload(false);

依存関係の読み込み

モデルがリソースに依存している場合は、両方のパッケージをロードできます。しかし、モデルが多くのリソースに依存している場合、非常に多くのパッケージを手動でロードする必要があるでしょうか? さらに悪いことに、どの依存関係パッケージが分からない場合はどうなるでしょうか。

したがって、依存関係情報を取得するにはメインパッケージが必要です

// 加载主包
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "主包包名");
// 获取主包清单
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
// 从清单中获取依赖信息并保存在一个字符串数组中
string[] strs = abManifest.GetAllDependencies("需要加载的包名");
// for循环或者foreach都可以循环加载依赖包
foreach (string str in strs)
{
    
    
	AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + str);
}

問題が発生しました。パッケージ本体を使用してリソースをロードします。ただし、別のパッケージの依存関係パッケージがこのパッケージの依存関係パッケージと同じである場合、別のパッケージをロードするとエラーが報告されます。同じ依存関係パッケージが 2 回ロードされるためです。

この問題を回避するには、リソース パッケージのロードとアンロードを一元管理する管理者が必要です。


AB パッケージ エクスプローラー

まず、リソース マネージャーが持つべき特性について考えてみましょう。

  • グローバルに一意です。そうでない場合は、他のクラスからの呼び出しによってロードが繰り返されます (シングル ケース モード)。
  • 辞書ストレージ、パッケージ本体の使用リスト、キーと値のペアのリストにより、繰り返しの書き込みを回避できます
  • メインスレッドの安全性を確保するための非同期ロード

その場合、シングルトン リソース マネージャーが最良の選択になります。

主なプロセスは 4 つのステップに分かれています。

  • メインパッケージを読み取って依存関係を取得する関数を作成する
  • パッケージ名と AB パッケージ リソース間のマッピングをキーと値のペアの形式で保存するディクショナリを定義すると、同じパッケージを繰り返し読み取ることがなくなります。
  • Unity の AB パッケージの読み取りメソッドを書き換えて、最初にメイン パッケージを読み取り、読み取った AB パッケージの依存関係を取得し、次に AB パッケージとすべての依存パッケージを読み取るようにします。
  • アンインストール方法を定義し、辞書をクリアします
  • (およびその他の拡張可能なカスタム メソッド)

ここにコードのほんの一部を示します。

ジェネリックスを受け入れるシングルトン基本クラス DontDestroyOnLoad を定義する

/// <summary>
/// 该单例继承于Mono,并且不会随着场景的切换而销毁
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class DDOLSingletonMono<T> : MonoBehaviour where T : MonoBehaviour
{
    
    
    private static T _instance;
    public static T Instance
    {
    
    
        get
        {
    
    
            if (_instance == null)
            {
    
    
                _instance = FindObjectOfType<T>();
                if (_instance == null)
                {
    
    
                    GameObject obj = new GameObject();
                    obj.name = typeof(T).Name;
                    DontDestroyOnLoad(obj);
                    _instance = obj.AddComponent<T>();
                }
            }
            return _instance;
        }
    }
}

ABManager を定義します。ABManager は上記の基本クラスを継承し、その中で管理メソッドを定義します。

    /// <summary>
    /// 加载AB包
    /// </summary>
    /// <param name="abName"></param>
    public void LoadAB(string abName)
    {
    
    
        // 获取主包
        if (mainAB == null)
        {
    
    
            mainAB = AssetBundle.LoadFromFile(PathUrl + MainABName);
            manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }
        AssetBundle ab = null;
        // 获取所用资源包依赖信息
        string[] relys = manifest.GetAllDependencies(abName);
        foreach (string rely in relys)
        {
    
    
            // 判断依赖包是否已加载
            if (!abDic.ContainsKey(rely))
            {
    
    
                ab = AssetBundle.LoadFromFile(PathUrl + rely);
                abDic.Add(rely, ab);
            }
        }
        // 加载资源包
        if (!abDic.ContainsKey(abName))
        {
    
    
            ab = AssetBundle.LoadFromFile(PathUrl + abName);
            abDic.Add(abName, ab);
        }
    }
    /// <summary>
    /// 异步加载资源,GameObject类型可直接帮助实例化
    /// </summary>
    /// <param name="abName">加载的资源包</param>
    /// <param name="resName">加载的资源名称</param>
    /// <param name="callBack"></param>
    public void LoadResAsync(string abName, string resName, UnityAction<Object> callBack)
    {
    
    
        StartCoroutine(LoadResAsyncCoroutine(abName, resName, callBack));
    }
    private IEnumerator LoadResAsyncCoroutine(string abName, string resName, UnityAction<Object> callBack)
    {
    
    
        LoadAB(abName);
        // 如果是GameObject,帮助实例化
        AssetBundleRequest abr = abDic[abName].LoadAssetAsync(resName);
        yield return abr;
        if (abr.asset == null)
        {
    
    
            Debug.LogError("异步加载失败!读取资源为空!");
        }
        if (abr.asset is GameObject)
            callBack(Instantiate(abr.asset));
        else
            callBack(abr.asset);
    }

他のコードも同様で、公式の 3 つの同期読み込みメソッドと非同期読み込みメソッドを書き換えて、最初に依存関係パッケージを読み取り、ゲームオブジェクトのインスタンス化を支援するだけです。特定のコードは、 [Tang Laoshi] Unity Hot Update AssetBundle
で確認できます。

AB パッケージ マネージャーを使用すると、プロジェクト内のパッケージ関係の混乱を避けることができます。5 つ星でお勧めします。

Supongo que te gusta

Origin blog.csdn.net/milu_ELK/article/details/131815540
Recomendado
Clasificación