当前位置:网站首页>AB package details in unity (super detail, features, packaging, loading, manager)

AB package details in unity (super detail, features, packaging, loading, manager)

2022-07-07 15:44:00 Listen to the rain outside the window

Unity Medium AssetBundle Detailed explanation

AssetBundle The concept of

AssetBundle also called AB package , yes Unity Provides a resource compression package for storing resources .

Unity Medium AssetBundle The system is an extension of resource management , By distributing resources in different AB The package can minimize the memory pressure at run time , You can dynamically load and unload AB package , Then selectively load the content .

AssetBundle The advantages of

  1. AB Package storage location customization , Then it can be put into a readable and writable path to facilitate hot update

  2. AB Package custom compression , You can choose not to compress or choose LZMA and LZ4 Equal compression mode , Reduce the size of the bag , Faster network transmission .

  3. Resources can be distributed in different AB In bag , Minimize memory pressure at runtime , It can be used and loaded immediately , Selectively load the required content .

  4. AB The package supports dynamic updates in the later stage , Significantly reduce the size of the initial installation package , Non core resources AB Upload the package to the server , Late runtime dynamic loading , Improve user experience .

AssetBundle and Resources Comparison

AssetBundleResources
Resources can be distributed in multiple packages All resources are packaged into a big package
Flexible customization of storage location It must be stored in Resources Under the table of contents
Flexible compression (LZMA,LZ4) All resources will be compressed into binary
Support dynamic update in later period After packaging, the resource is read-only and cannot be changed dynamically

AssetBundle Characteristics of

  1. AB Packages can store most Unity Resources but cannot be stored directly C# Script , So the hot update of code needs to use Lua Or store the compiled DLL file .

  2. AB Packages cannot be loaded repeatedly , When AB After the package has been loaded into memory, it must be unloaded before it can be reloaded .

  3. Multiple resources are distributed in different AB The package may have some resources such as the mapping of a prefab that are not under the same package , Direct loading will cause some resources to be lost , namely AB There are dependencies between packages , Loading the current AB Packages need to be loaded together with the packages they depend on .

  4. After packing , A main package will be automatically generated ( The name of the main package varies with the platform ), The main package is manifest The version number will be stored under 、 Check code (CRC)、 Information about all other packages ( name 、 Dependency relationship )
     Insert picture description here

AssetBundle Full packaging process

This is mainly about Unity Official AB Package management plug-in AssetBundle Browser package

1、AssetBundleBrowser Access to plug-ins

  1. Unity 2019 The version can be directly in Windows —> PackageManager Find this plug-in inside and install it directly

  2. 2020 After version or other versions may be 1 The plug-in cannot be found in the method , You can go to github Search and download compressed packages , Download address https://github.com/Unity-Technologies/AssetBundles-Browser

 Insert picture description here

Unzip the downloaded installation package to Unity engineering Packages Under the folder ( Be sure to decompress )

 Insert picture description here

2、AssetBundleBrowser Use of panels

  • After getting and installing the plug-in correctly , adopt Windows ----> AssetBundle Browser Open down AB Package management panel There are three panels

  • Configure panel : Can view the current AB Basic information about the package and its internal resources ( size , resources , Dependence, etc )

    [ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-7iIL4QAL-1644109483100)( Summary of knowledge points 2-AB package .assets/image-20220127124332879-16432586143164.png)]

  • Build panel : be responsible for AssetBundle Packaging related settings Press Build You can pack it

    [ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-Mp5AKQsC-1644109483100)( Summary of knowledge points 2-AB package .assets/image-20220127151926768-16432679678095.png)]

    Three compression methods

    1. NoCompression: Uncompressed , Fast decompression , Big bag , Not recommended .
    2. LZMA: Minimum compression , Slow decompression , Use one resource to decompress all resources in the package .
    3. LZ4: Slightly larger compression , Fast decompression , Decompress whatever you use , Low memory usage , It is more recommended to use .

    Generally, the settings that need to be changed are the relevant option settings checked in the figure .

  • Inspect panel : It is mainly used to view the packaged AB Some details of the package file ( size , Resource path, etc )

 Insert picture description here

3、 Set the AssetBundle package

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-z08RRDsL-1644109483101)( Summary of knowledge points 2-AB package .assets/image-20220127153106012-16432686679037.png)]

In the case of resources that need to be packaged Inspector Under the panel, you can choose where it should be placed AB It's a bag , Can also pass New newly build AB Package puts resources into , Put it in again Build Packaging can put this resource into the corresponding AB In bag .

AssetBundle Manager

​ utilize AssetBundleBrowser Can be easily implemented AB Package work , More importantly, how to AB Load the resources in the package and use them ,Unity A set of API Can achieve AB Package loading and resource loading .

AB The main requirements of package manager : Load specified AB The specified resources under the package , The basic steps are as follows :

  1. Load the resource AB Package and all its dependent packages ( According to the main package manifest Information find dependent package name )
  2. from AB Load the specified resource in the package ( By name , type )
  3. Unload the loaded when it is no longer in use AB package

Mainly related API

//AB Package loading required related API
//1.  Load according to the path AB package   Be careful AB Packages cannot be loaded repeatedly 
AssetBundle ab = AssetBundle.LoadFromFile(path);
//2.  load ab Resources with specified names and types under the package 
T obj = ab.LoadAsset<T>(ResourceName); // Generic loading 
Object obj = ab.LoadAsset(ResourceName); // Non generic loading   The type of forced rotation is required for subsequent use 
Object obj = ab.LoadAsset(ResourceName,Type); // The parameter indicates the resource type   Prevent duplicate names 
T obj = ab.LoadAssetAsync<T>(resName); // Asynchronous generic loading 
Object obj = ab.LoadAssetAsync(resName); // Asynchronous non generic loading 
Object obj = ab.LoadAssetAsync(resName,Type); // The parameter indicates the resource type   Prevent duplicate names 
//3.  uninstall ab package  bool The parameter represents whether the deletion has been made from AB Resources loaded into the scene in the package ( It's usually false)
ab.UnLoad(false); // Uninstall a single ab package 
AssetBundle.UnloadAllAssetBundles(false); // Uninstall all AB package 

Here is AB Detailed code and comments of package manager , The content of the singleton mode involved in it will be briefly introduced later .

ABManager.cs

using System;
using System.Net.Mime;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Common
{
    
    /// <summary>
    /// AB Package manager   Globally unique   Use singleton mode 
    /// </summary>
    public class ABManager : MonoSingleton<ABManager>
    {
    
        //AB Package cache --- solve AB The package cannot be loaded repeatedly   It is also conducive to improving efficiency .
        private Dictionary<string, AssetBundle> abCache;

        private AssetBundle mainAB = null; // Main package 

        private AssetBundleManifest mainManifest = null; // Configuration files in the main package --- To obtain dependent packages 

        // The basic path under each platform  ---  Use macros to judge streamingAssets route 
        private string basePath {
     get
            {
    
            // Use StreamingAssets Path note AB When packing   Check copy to streamingAssets
#if UNITY_EDITOR || UNITY_STANDALONE
                return Application.dataPath + "/StreamingAssets/";
#elif UNITY_IPHONE
                return Application.dataPath + "/Raw/";
#elif UNITY_ANDROID
                return Application.dataPath + "!/assets/";
#endif
            }
        }
        // The name of the main package under each platform  ---  It is used to load the main package to obtain dependency information 
        private string mainABName
        {
    
            get
            {
    
#if UNITY_EDITOR || UNITY_STANDALONE
                return "StandaloneWindows";
#elif UNITY_IPHONE
                return "IOS";
#elif UNITY_ANDROID
                return "Android";
#endif
            }
        }

        // It inherits the initialization function provided by the singleton mode 
        protected override void Init()
        {
    
            base.Init();
            // Initialize Dictionary 
            abCache = new Dictionary<string, AssetBundle>();
        }


        // load AB package 
        private AssetBundle LoadABPackage(string abName)
        {
    
            AssetBundle ab;
            // load ab package , You need to load its dependent packages .
            if (mainAB == null)
            {
    
                // Load the main package according to the basic path and main package name under each platform 
                mainAB = AssetBundle.LoadFromFile(basePath + mainABName);
                // Get the AssetBundleManifest Resource file ( There is dependent information )
                mainManifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
            }
            // according to manifest Get the names of all dependent packages   Fix API
            string[] dependencies = mainManifest.GetAllDependencies(abName);
            // Cycle through all dependent packages 
            for (int i = 0; i < dependencies.Length; i++)
            {
    
                // If it is not in the cache, add 
                if (!abCache.ContainsKey(dependencies[i]))
                {
    
                    // Load according to the dependent package name 
                    ab = AssetBundle.LoadFromFile(basePath + dependencies[i]);
                    // Pay attention to adding to the cache   Prevent duplicate loading AB package 
                    abCache.Add(dependencies[i], ab);
                }
            }
            // Load the target package  --  Similarly, pay attention to the cache problem 
            if (abCache.ContainsKey(abName)) return abCache[abName];
            else
            {
    
                ab = AssetBundle.LoadFromFile(basePath + abName);
                abCache.Add(abName, ab);
                return ab;
            }


        }
        
        
        //================== Three resource synchronous loading methods ==================
        // Provide a variety of calling methods   It is convenient for other languages to call (Lua Bad support for generics )
        #region  Three overloads loaded synchronously 
        
        /// <summary>
        ///  Load resources synchronously --- Generic loading   Simple and intuitive   No need to show the conversion 
        /// </summary>
        /// <param name="abName">ab The name of the package </param>
        /// <param name="resName"> Resource name </param>
        public T LoadResource<T>(string abName,string resName)where T:Object
        {
    
            // Load the target package 
            AssetBundle ab = LoadABPackage(abName);

            // Returns the resource 
            return ab.LoadAsset<T>(resName);
        }

        
        // Do not specify type   It is not recommended to use when there are duplicate names   The conversion type should be displayed when using 
        public Object LoadResource(string abName,string resName)
        {
    
            // Load the target package 
            AssetBundle ab = LoadABPackage(abName);

            // Returns the resource 
            return ab.LoadAsset(resName);
        }
        
        
        // Use parameters to pass types , Suitable for language calls that are not supported by generics , Forced rotation type is required when using 
        public Object LoadResource(string abName, string resName,System.Type type)
        {
    
            // Load the target package 
            AssetBundle ab = LoadABPackage(abName);

            // Returns the resource 
            return ab.LoadAsset(resName,type);
        }

        #endregion
        
        
        //================ There are three ways to load resources asynchronously ======================

        /// <summary>
        ///  Provide asynchronous loading ---- Be careful   This loading AB Packages are loaded synchronously , Just loading resources is asynchronous 
        /// </summary>
        /// <param name="abName">ab Package name </param>
        /// <param name="resName"> Resource name </param>
        public void LoadResourceAsync(string abName,string resName, System.Action<Object> finishLoadObjectHandler)
        {
    
            AssetBundle ab = LoadABPackage(abName);
            // Start the process   Provide the delegation after the resource is loaded successfully 
            StartCoroutine(LoadRes(ab,resName,finishLoadObjectHandler));
        }

        
        private IEnumerator LoadRes(AssetBundle ab,string resName, System.Action<Object> finishLoadObjectHandler)
        {
    
            if (ab == null) yield break;
            // Load resources asynchronously API
            AssetBundleRequest abr = ab.LoadAssetAsync(resName);
            yield return abr;
            // Delegate call processing logic 
            finishLoadObjectHandler(abr.asset);
        }
        
        
        // according to Type Load resources asynchronously 
        public void LoadResourceAsync(string abName, string resName,System.Type type, System.Action<Object> finishLoadObjectHandler)
        {
    
            AssetBundle ab = LoadABPackage(abName);
            StartCoroutine(LoadRes(ab, resName,type, finishLoadObjectHandler));
        }
        
       	
        private IEnumerator LoadRes(AssetBundle ab, string resName,System.Type type, System.Action<Object> finishLoadObjectHandler)
        {
    
            if (ab == null) yield break;
            AssetBundleRequest abr = ab.LoadAssetAsync(resName,type);
            yield return abr;
            // Delegate call processing logic 
            finishLoadObjectHandler(abr.asset);
        }

        
        // Generic loading 
        public void LoadResourceAsync<T>(string abName, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object
        {
    
            AssetBundle ab = LoadABPackage(abName);
            StartCoroutine(LoadRes<T>(ab, resName, finishLoadObjectHandler));
        }

        private IEnumerator LoadRes<T>(AssetBundle ab, string resName, System.Action<Object> finishLoadObjectHandler)where T:Object
        {
    
            if (ab == null) yield break;
            AssetBundleRequest abr = ab.LoadAssetAsync<T>(resName);
            yield return abr;
            // Delegate call processing logic 
            finishLoadObjectHandler(abr.asset as T);
        }


        //====================AB There are two ways to uninstall packages =================
        // Single package uninstall 
        public void UnLoad(string abName)
        {
    
            if(abCache.ContainsKey(abName))
            {
    
                abCache[abName].Unload(false);
                // Note that the cache should be removed together 
                abCache.Remove(abName);
            }
        }

        // Uninstall all packages 
        public void UnLoadAll()
        {
    
            AssetBundle.UnloadAllAssetBundles(false);
            // Pay attention to emptying the cache 
            abCache.Clear();
            mainAB = null;
            mainManifest = null;
        }
    }
}

The script singleton class inherited by the above manager is as follows

MonoSingleton.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Common
{
    
    ///<summary>
    /// Script singleton class , Responsible for creating instances for unique scripts 
    ///<summary>

    public class MonoSingleton<T> : MonoBehaviour where T:MonoSingleton<T> // Note that this constraint is T Must be itself or a subclass 
    {
    
        /*  Instead of creating an instance directly in a script that needs to be uniquely created ,Awake Problems to be solved in the initialization process  1. Duplicate code  2. stay Awake Initialization inside , Other scripts are in Awake It may be called in Null Abnormal conditions of  */

        // solve 1: Creating instances using generics   solve 2: Use load on demand ( That is, when there are other script calls get Load in )

        private static T instance; // Create private object record value , You can assign values only once to avoid multiple assignments 

        public static T Instance
        {
    
            // Implement on-demand loading 
            get
            {
    
                // When it has been assigned , You can go back directly 
                if (instance != null) return instance;

                instance = FindObjectOfType<T>();

                // To prevent the script from hanging on the object , Exception not found , You can create an empty object and hang it 
                if (instance == null)
                {
    
                    // If you create an object , The script on it will be called when it is created Awake That is to call T Of Awake(T Of Awake Is actually the name of the inherited parent class )
                    // So there is no need to instance assignment , It will be in Awake Assignment in , It will initialize naturally, so there is no need to init()
                    /*instance = */
                    new GameObject("Singleton of "+typeof(T)).AddComponent<T>();
                }
                else instance.Init(); // Guarantee Init Only once 

                return instance;

            }
        }

        private void Awake()
        {
    
            // If there are no other scripts Awake Call this instance , Then you can Awake Self initialization in instance
            instance = this as T;
            // initialization 
            Init();
        }

        // Subclasses initialize members if placed in Awake There will still be Null So make one by yourself init Function solution ( It's not necessary to use it )
        protected virtual void Init()
        {
    

        }
    }

}

In addition to the script singleton class above There are two other singleton patterns that do not need inheritance MonoBehaviour Pure C# The singleton pattern Interested readers can learn about Hungry and lazy mode in singleton mode .

原网站

版权声明
本文为[Listen to the rain outside the window]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202130610501294.html