当前位置: 首页 > news >正文

unityAB包(2/2)

unityAB包(2/2)

    • unity
      • 1.AB包的依赖问题
      • 2.AB包资源管理器
        • 先导:饿汉模式与懒汉模式
          • 饿汉模式
          • 懒汉模式
        • AB资源管理器主代码

unity

1.AB包的依赖问题

例如一个Prefab被添加到了AB包中,该包会默认添加这个预设体带有的材质等,然而如果你手动把相关的材质添加到了另外的AB包中,此时该材质就不会添加到预设体的AB包中(可能是出于性能考虑机制),则一定要引用预设体对应的包和材质所对应的包,否则会出现材质错误。

然而显而易见的是当这个预设体的引用来自各个不同的AB包中,那么一条一条引入包的代码就会显得很冗余。所以引入了下面这个方法。

通过给定的API得到所有依赖的信息,然后用一个string数组存储这些依赖包的名字,通过遍历依赖名字数组导入所有的依赖。

AssetBundle abMain = AssetBundle.LoadFromFile (Application.streamingAssetsPath + "/" + "PC");
// 加载主包中的固定文件
AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
// 从固定文件中 得到依赖信息
string [] strs = abManifest.GetAllDependencies ("model");
// 得到了 依赖包的名字
for (int i = 0; i < strs.Length; i++)
{
	AssetBundle.LoadFromFile (Application.streamingAssetsPath
	 + "/" + strs [i]);
}

这种方法不能对一个AB包中的预设体进行区分,例如A刚需EF包,B刚需OL包,
然而我项目中只使用了A,然而在检查依赖的时候会一同加载不被需要的OL包。

2.AB包资源管理器

先导:饿汉模式与懒汉模式
饿汉模式

在类建立之初就创建一个只读的对象,确保唯一。

using UnityEngine;

public class EagerSingleton : MonoBehaviour
{
    // 静态字段,用于存储单例实例
    public static EagerSingleton instance;

    private void Awake()
    {
        // 在Awake方法中进行实例的初始化
        if (instance == null)
        {
            instance = this;
            // 确保单例对象在场景切换时不会被销毁
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            // 如果已经存在实例,则销毁当前对象
            Destroy(gameObject);
        }
    }
}
懒汉模式

引用自:博主YY-nb直达
确保只有在类的内部才能实例化,外部只能调用Instance方法。
使用lock确保在同一时间内只有一个进程在执行创建单例。
如果后续还有访问这个单例的,直接返回这个单例,不要再继续加锁了,影响性能。

public class Singleton
{
    private static Singleton instance;
    private static readonly object locker = new object();
    private Singleton(){}

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (locker)
                {
                    if (instance == null)
                        instance = new Singleton();                    
                }
            }
            return instance;
        }       
    }
}

AB资源管理器主代码
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class AssetBundleManager : MonoBehaviour
{

    public static AssetBundleManager Instance;
    private Dictionary<string, AssetBundle> abDic;
    private AssetBundle mainAB = null;
    private AssetBundleManifest mainfest = null;
    public string abUrl { get; private set; }
    public string mainAbName { get; private set; }
    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if(Instance != this)
        {
            Destroy(gameObject);
        }
    }

    private void Start()
    {
        abDic = new Dictionary<string, AssetBundle>();
        abUrl = Application.streamingAssetsPath + "/";
        mainAbName = "PC";
    }
    //加载依赖
    public void LoadDepends(string abName)
    {
        //获取主包
        if(mainAB == null)
        {
             mainAB = AssetBundle.LoadFromFile(abUrl + mainAbName);        //固定语法 获取AB包配置文件
             mainfest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }
       
        string[] temp = mainfest.GetAllDependencies(abName);//主包API获取小包的依赖
        for(int i = 0; i < temp.Length; i++)
        {
            if (!abDic.ContainsKey(temp[i]))
            {
                AssetBundle tempab = AssetBundle.LoadFromFile(abUrl + temp[i]);//某个小包 依赖了这么多小包
                abDic.Add(temp[i], tempab);
            }
            else
            {
                Debug.Log("again");
            }
            
        }
        if (!abDic.ContainsKey(abName))
        {
            AssetBundle ab = AssetBundle.LoadFromFile(abUrl + abName);
            abDic.Add(abName, ab);
        }
        else
        {
            Debug.Log("again");
        }
    }


    // 同步加载
    public T LoadRes<T>(string abName, string resName) where T : Object
    {
        Debug.Log("YSe");
        LoadDepends(abName);

        T res = abDic[abName].LoadAsset<T>(resName);
        return res;
    }
    // 异步加载
    // 异步加载依赖
    public IEnumerator LoadDependsAsync(string abName)
    {
        // 获取主包
        if (mainAB == null)
        {
            AssetBundleCreateRequest mainABRequest = AssetBundle.LoadFromFileAsync(abUrl + mainAbName);
            yield return mainABRequest;
            mainAB = mainABRequest.assetBundle;
            mainfest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        }
        //只要涉及获取等待的任务 都需要一个yield return
        string[] temp = mainfest.GetAllDependencies(abName);
        for (int i = 0; i < temp.Length; i++)
        {
            if (!abDic.ContainsKey(temp[i]))
            {
                AssetBundleCreateRequest tempAbRequest = AssetBundle.LoadFromFileAsync(abUrl + temp[i]);
                yield return tempAbRequest;
                AssetBundle tempab = tempAbRequest.assetBundle;
                abDic.Add(temp[i], tempab);
            }
            else
            {
                Debug.Log("again");
            }
        }

        if (!abDic.ContainsKey(abName))
        {
            AssetBundleCreateRequest abRequest = AssetBundle.LoadFromFileAsync(abUrl + abName);
            yield return abRequest;
            AssetBundle ab = abRequest.assetBundle;
            abDic.Add(abName, ab);
        }
        else
        {
            Debug.Log("again");
        }
    }

    // 异步加载资源
    public IEnumerator LoadResAsync<T>(string abName, string resName, System.Action<T> onComplete) where T : Object
    {
        yield return StartCoroutine(LoadDependsAsync(abName));

        AssetBundleRequest request = abDic[abName].LoadAssetAsync<T>(resName);
        yield return request;

        T res = abDic[abName].LoadAsset<T>(resName);

        onComplete?.Invoke(res);
    }



    // 卸载单个包
    public void UnLoad(string abName)
    {
        abDic[abName].Unload(false);
        abDic.Remove(abName);
    }
    // 卸载所有包
    public void UnLoadAll()
    {
        AssetBundle.UnloadAllAssetBundles(false);
        abDic.Clear();
        mainAB = null;
        mainfest = null;
    }
}


TEST脚本

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

public class Test : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //同步
        GameObject gameObject = AssetBundleManager.Instance.LoadRes<GameObject>("model", "Cube");
        Instantiate(gameObject,Vector3.up,Quaternion.identity);
        GameObject gameObject2 = AssetBundleManager.Instance.LoadRes<GameObject>("model", "Cube");
        Instantiate(gameObject2, Vector3.down, Quaternion.identity);
        //异步
        StartCoroutine(AssetBundleManager.Instance.LoadResAsync<GameObject>("model", "Cube", OnAssetLoaded));
    }
	//根据传出类型的不同 编写不同的OnXXX函数,然后订阅此函数
    private void OnAssetLoaded(GameObject loadedAsset)
    {
        if (loadedAsset != null)
        {
            // 资源加载成功,实例化该资源
            Instantiate(loadedAsset);
            Debug.Log("资源加载并实例化成功!");
        }
        else
        {
            Debug.LogError("资源加载失败!");
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

相关文章:

  • 性能测试笔记
  • asp.net进销存软件WEB进销存ERP软件库存玻璃行业
  • MySQL 5.7升级8.0报异常:处理新增关键字
  • [ACTF2020 新生赛]BackupFile-3.23BUUCTF练习day5(1)
  • 【北京大学】DeepSeek内部研讨系列:DeepSeek原理和落地应用
  • Linux shell脚本3-if语句、case语句、for语句、while语句、until语句、break语句、continue语句,格式说明及程序验证
  • 使用Ollama(自定义安装位置)与RagFlow构建本地知识库
  • 跟着StatQuest学知识07-张量与PyTorch
  • 【leetcode hot 100 34】在排序数组中查找元素的第一个和最后一个位置
  • LLM-01-第一章-预训练/神经网络的激活函数(一)概述
  • 信息安全和病毒防护——非对称加密和对称加密
  • 在 SaaS 应用上构建 BI 能力的实战之路
  • Ciallo~ (∠・ω< )⌒★
  • 【redis】主从复制:单点问题、配置详解、特点详解
  • 阻塞队列:原理、应用及实现
  • 第十六届蓝桥杯康复训练--8
  • 学习记录-vue2,3-vue实现tab栏
  • 齿轮啮合频率计算及其频谱图
  • [C语言基础] 第2章 算法的概念
  • kube-score K8S Yaml静态代码分析工具详解
  • 张建华评《俄国和法国》|埃莲娜·唐科斯的俄法关系史研究
  • 澎湃读报丨央媒头版头条集中刊发:大国应有的样子
  • 阿曼外交部:美伊谈判因故推迟
  • 腾讯重构混元大模型研发体系:成立大语言和多模态模型部,提升AI长期技术作战能力
  • 这座“蚌埠住了”的城市不仅会接流量,也在努力成为文旅实力派
  • 国家统计局:一季度全国规模以上文化及相关产业企业营业收入增长6.2%