IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity AssetBundle分包 -> 正文阅读

[游戏开发]Unity AssetBundle分包

一、Unity AssetBundle分包流程图

在这里插入图片描述

二、源码

AssetBundleGroupGetter对象,负责分组管理

using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class AssetBundleGroupGetter
{
    /// <summary>
    /// 所有资源的AssetInfo
    /// </summary>
    private static Dictionary<string, AssetInfo> assetInfoDict = new Dictionary<string, AssetInfo>();

    /// <summary>
    /// 分过组的AssetInfo  key=>头部文件  value=>所有仅被头部文件引用的子依赖列表
    /// </summary>
    private static Dictionary<AssetInfo, List<AssetInfo>> assetGroupInfoDict =
        new Dictionary<AssetInfo, List<AssetInfo>>();

    private static string progressTitle;
    private static float progress;

    

    public static List<List<string>> GetAllUncompressedGroup()
    {
        List<List<string>> list = new List<List<string>>();
        int index = 0;
        foreach(var ais in assetGroupInfoDict)
        {
            if(ais.Key.assetType != AssetType.Video) continue;
            index = list.Count;
            list.Add(new List<string>());
            list[index].Add(ais.Key.path);
            foreach(var ai in ais.Value)
            {
                list[index].Add(ai.path);
            }
        }
        return list;
    }
    public static List<List<string>> GetAllGroup()
    {
        List<List<string>> list = new List<List<string>>();
        int index = 0;
        foreach(var ais in assetGroupInfoDict)
        {
            if(ais.Key.assetType == AssetType.Video) continue;
            index = list.Count;
            list.Add(new List<string>());

            if(ais.Key.assetType != AssetType.SpriteAtlas)
                list[index].Add(ais.Key.path);
            foreach(var ai in ais.Value)
            {
                list[index].Add(ai.path);
            }
        }
        return list;
    }

    /// <summary>
    /// 打Bundle初始化
    /// </summary>
    public static void InitBuild(string assetPath)
    {
        assetInfoDict.Clear();
        assetGroupInfoDict.Clear();
        progressTitle = "分析依赖";
        InitAllAssetInfo(assetPath);
        progressTitle = "资源分组";
        AllAssetInfoToGroup();
        EditorUtility.ClearProgressBar();
    }


    private static void ShowProgress(string title, string info, float progress)
    {
        EditorUtility.DisplayProgressBar(title, info, progress);
    }


    /// <summary>
    /// 实例化所有的AssetInfo
    /// </summary>
    private static void InitAllAssetInfo(string assetPath)
    {
        string[] allFileArr = Directory.GetFiles(assetPath, "*", SearchOption.AllDirectories);
        int allFileCount = allFileArr == null ? 0 : allFileArr.Length;

        for (int i = 0; i < allFileCount; i++)
        {
            string filePath = allFileArr[i];
            progress = (float) i / allFileCount;
            ShowProgress(progressTitle, filePath, progress);
            if (filePath.EndsWith(".meta"))
            {
                continue;
            }

            filePath = filePath.Replace("\\", "/");
            CreateAssetInfo(filePath, null);
        }
    }

    /// <summary>
    /// 生成AssetInfo
    /// </summary>
    /// <param name="path">AssetInfo的路径</param>
    /// <param name="parent">父依赖</param>
    private static void CreateAssetInfo(string path, AssetInfo parent = null)
    {
        AssetInfo info = null;
        if (assetInfoDict.ContainsKey(path))
        {
            info = assetInfoDict[path];
        }
        else
        {
            info = new AssetInfo(path);
            assetInfoDict.Add(path, info);
        }

        if (parent != null)
        {
            parent.AddChild(info);
            //文件的父级Scene文件不记录依赖关系
            if (parent.assetType != AssetType.Scene)
            {
                info.AddParent(parent);
            }
        }

        List<string> depends = info.GetDepends();

        if (depends != null && depends.Count > 0)
        {
            foreach (var item in depends)
            {
                CreateAssetInfo(item, info);
            }
        }
    }

    /// <summary>
    /// 对所有AssetInfo进行分组
    /// </summary>
    private static void AllAssetInfoToGroup()
    {
        int assetCount = assetInfoDict == null ? 0 : assetInfoDict.Count;
        int id = 0;
        if (assetCount > 0)
        {
            foreach (var item in assetInfoDict)
            {
                AssetInfo info = item.Value;
                AssetInfoToGroup(info);
                progress = (float) id / assetCount;
                
                
                ShowProgress(progressTitle, info.path, progress);
                id++;
            }
        }
    }

    /// <summary>
    /// AssetInfo进行分组
    /// </summary>
    /// <param name="info"></param>
    private static void AssetInfoToGroup(AssetInfo info)
    {
        if (info.isGrouped)
        {
            return;
        }

        bool isTop = info.IsTop();
        if (isTop) //是顶级文件
        {
            AddAssetGroupInfoDict(info, null);
            return;
        }

        AssetInfo atlasInfo = info.GetBelongSpriteAtlas();
        if (atlasInfo != null) //此文件已经被打进了图集
        {
            AddAssetGroupInfoDict(atlasInfo, info);
            return;
        }

        List<AssetInfo> topParentList = info.FindTopParent();
        if (topParentList.Count == 1) //只有一个顶级父文件,那么这个文件和顶级父文件分成一个组
        {
            AddAssetGroupInfoDict(topParentList[0], info);
        }
        else
        {
            //所有当前文件的顶级父物体共同拥有的子依赖
            List<AssetInfo> crossChildInfo = FindMultipleParentCrossChilds(topParentList);
            for (int i = crossChildInfo.Count - 1; i >= 0; i--)
            {
                AssetInfo crossInfo = crossChildInfo[i];
                if (crossInfo.isGrouped)
                {
                    crossChildInfo.Remove(crossInfo);
                    continue;
                }

                List<AssetInfo> crossChildInfoTopParentList = crossInfo.FindTopParent();
                int count = crossChildInfoTopParentList == null ? 0 : crossChildInfoTopParentList.Count;
                if (count != topParentList.Count) //这个共同子文件中间也被其他顶级文件引用
                {
                    crossChildInfo.Remove(crossInfo);
                }
            }

            //把这些被多个顶级父文件共同依赖的文件分成一组
            if (crossChildInfo.Count > 0)
            {
                //随表找一个文件来占分组字典的坑位
                AssetInfo headInfo = crossChildInfo[0];
                crossChildInfo.RemoveAt(0);
                AddAssetListGroupInfoDict(headInfo, crossChildInfo);
            }
        }
    }

    /// <summary>
    /// 将文件加入分组字典
    /// </summary>
    /// <param name="headInfo">头部文件,即为Key</param>
    /// <param name="childInfo">依赖文件</param>
    private static void AddAssetGroupInfoDict(AssetInfo headInfo, AssetInfo childInfo)
    {
        if (headInfo == null)
        {
            return;
        }

        if (!assetGroupInfoDict.ContainsKey(headInfo))
        {
            assetGroupInfoDict.Add(headInfo, new List<AssetInfo>());
            headInfo.isGrouped = true;
        }

        if (childInfo != null && !childInfo.isGrouped)
        {
            assetGroupInfoDict[headInfo].Add(childInfo);
            childInfo.isGrouped = true;
        }
    }

    private static void AddAssetListGroupInfoDict(AssetInfo headInfo, List<AssetInfo> childInfoList)
    {
        if (childInfoList == null || childInfoList.Count == 0)
        {
            AddAssetGroupInfoDict(headInfo, null);
            return;
        }

        for (int i = 0; i < childInfoList.Count; i++)
        {
            AssetInfo childInfo = childInfoList[i];
            AddAssetGroupInfoDict(headInfo, childInfo);
        }
    }
    
    /// <summary>
    /// 获取多个父文件共同依赖的子文件
    /// </summary>
    /// <param name="parentList"></param>
    /// <returns></returns>
    private static List<AssetInfo> FindMultipleParentCrossChilds(List<AssetInfo> parents)
    {
        if (parents == null || parents.Count < 2)
        {
            return null;
        }

        List<AssetInfo> list = parents[0].childList;
        if (list == null || list.Count == 0)
        {
            return null;
        }

        for (int i = 1; i < parents.Count; i++)
        {
            List<AssetInfo> childs = parents[i].childList;
            if (childs == null || childs.Count == 0)
            {
                return null;
            }

            list = list.Intersect(childs).ToList();
            if (list == null || list.Count == 0)
            {
                return null;
            }
        }

        return list;
    }

    /// <summary>
    /// 获得多个子文件共同拥有的父文件
    /// </summary>
    /// <param name="childs"></param>
    /// <returns></returns>
    private static List<AssetInfo> FindMultipleChildCrossParents(List<AssetInfo> childs)
    {
        if (childs == null || childs.Count < 2)
        {
            return null;
        }

        List<AssetInfo> list = childs[0].parentList;
        if (list == null || list.Count == 0)
        {
            return null;
        }

        for (int i = 1; i < childs.Count; i++)
        {
            List<AssetInfo> parents = childs[i].parentList;
            if (parents == null || parents.Count == 0)
            {
                return null;
            }

            list = list.Intersect(parents).ToList();
            if (list == null || list.Count == 0)
            {
                return null;
            }
        }

        return list;
    }

}


AssetInfo对象 这是一个文件对象,每一个资源文件对应一个AssetInfo

using System.Collections.Generic;
using System.IO;
using UnityEditor;
using Object = UnityEngine.Object;

public enum AssetType{
    //图集
    SpriteAtlas,
    //图片(精灵、贴图)
    Image,
    //预制体
    Prefab,
    //音频
    Audio,
    //视频
    Video,
    //场景
    Scene,
    //其他
    Other,
}

public class AssetInfo
{
    /// <summary>
    /// 是否已经分组
    /// </summary>
    public bool isGrouped = false;
    
    //资源类型
    public AssetType assetType;
    /// <summary>
    /// 文件路径
    /// </summary>
    public string path;
    /// <summary>
    /// 所有的父依赖文件
    /// </summary>
    public List<AssetInfo> parentList;
    /// <summary>
    /// 所有的子依赖文件
    /// </summary>
    public List<AssetInfo> childList;
    
    public AssetInfo(string _path)
    {
        path = _path;
        SetAssetType();
    }

    /// <summary>
    /// 设置文件类型
    /// </summary>
    private void SetAssetType()
    {
        string suffix = Path.GetExtension(path);
        switch (suffix)
        {
            case ".prefab":
                assetType = AssetType.Prefab;
                break;
            case ".spriteatlas":
                assetType = AssetType.SpriteAtlas;
                break;
            case ".png":
            case ".jpg":
            case ".psd":
            case ".tiff":
            case ".tga":
            case ".gif":
                assetType = AssetType.Image;
                break;
            case ".mp3":
            case ".aif":
            case ".wav":
            case ".ogg":
                assetType = AssetType.Audio;
                break;
            case ".mp4":
            case ".mov":
            case ".mpg":
            case ".mpeg":
            case ".avi":
            case ".asf":
                assetType = AssetType.Video;
                break;
            case ".unity":
                assetType = AssetType.Scene;
                break;
            default:
                assetType = AssetType.Other;
                break;
        }
    }

    /// <summary>
    /// 添加父级文件
    /// </summary>
    /// <param name="info"></param>
    public void AddParent(AssetInfo info)
    {
        if (parentList==null)
        {
            parentList= new List<AssetInfo>();
        }
        if (!parentList.Contains(info))
        {
            parentList.Add(info);
        }
    }

    /// <summary>
    /// 添加子级文件
    /// </summary>
    /// <param name="info"></param>
    public void AddChild(AssetInfo info)
    {
        if (childList==null)
        {
            childList= new List<AssetInfo>();
        }
        if (!childList.Contains(info))
        {
            childList.Add(info);
        }
    }

    /// <summary>
    /// 得到最顶层的父级
    /// </summary>
    /// <returns></returns>
    public List<AssetInfo> FindTopParent()
    {
        List<AssetInfo> list = new List<AssetInfo>();
        if (IsTop())
        {
            return list;
        }
        for (int i = 0; i < parentList.Count; i++)
        {
            AssetInfo info = parentList[i];
            if (info.parentList==null||info.parentList.Count==0)
            {
                list.Add(info);
            }
        }
        return list;
    }

    /// <summary>
    /// 是不是顶级文件
    /// </summary>
    /// <returns></returns>
    public bool IsTop()
    {
        return parentList==null||parentList.Count==0;
    }

    /// <summary>
    /// 得到该文件所属的图集文件
    /// </summary>
    /// <returns></returns>
    public AssetInfo GetBelongSpriteAtlas()
    {
        AssetInfo atlasInfo = null;
        if (assetType!=AssetType.Image||IsTop())
        {
            return atlasInfo;
        }
        for (int i = 0; i < parentList.Count; i++)
        {
            AssetInfo parentInfo = parentList[i];
            if (parentInfo.assetType==AssetType.SpriteAtlas)
            {
                atlasInfo = parentInfo;
                break;
            }
        }
        return atlasInfo;
    }

    /// <summary>
    /// 得到最底层的子依赖
    /// </summary>
    /// <returns></returns>
    public List<AssetInfo> FindBottomChild()
    {
        List<AssetInfo> list = new List<AssetInfo>();
        if (childList==null||childList.Count==0)
        {
            return list;
        }
        for (int i = 0; i < parentList.Count; i++)
        {
            AssetInfo info = childList[i];
            if (info.childList==null||info.childList.Count==0)
            {
                list.Add(info);
            }
        }
        return list;
    }
    
    /// <summary>
    /// 获取目标物体所有的依赖
    /// </summary>
    /// <param name="objPath">目标物体路径(Assets/xx/xx.abc)</param>
    /// <returns></returns>
    public List<string> GetDepends()
    {
        List<string> list = null;
        string[] dependArr =AssetDatabase.GetDependencies(path,true);
        if (dependArr!=null&&dependArr.Length>0)
        {
            list=new List<string>();
            foreach (var dependPath in dependArr)
            {
                if (string.IsNullOrEmpty(Path.GetExtension(dependPath)))
                    continue;
                Object obj = AssetDatabase.LoadMainAssetAtPath(dependPath);
                if (obj is MonoScript || obj is LightingDataAsset)
                    continue;
                if (dependPath == path)
                    continue;
                if (dependPath.EndsWith(".cs"))
                    continue;
                if (!dependPath.StartsWith("Assets"))
                    continue;
                if (!list.Contains(dependPath))
                {
                    list.Add(dependPath);
                }
                
            }
        }
        return list;
    }
}




  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 13:27:57  更:2022-02-16 13:28:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 16:29:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码