unity傻瓜式打包assetsbundle

制作assetbundle是手游的必备技能,作者在这里分享一下自己写的用的工具类根据当前项目选择的平台,打包对应的资源包,并保存assetsbundle的相关信息进json文件里可以在tool这里选择打包resource下的资源(代码可以修改为其他目录,已经作为常量,便于修改)也可以在project面板里选择具体的文件夹右键那么他就会打包在StreamingAssets里贴一下代码,主要的类,这个类需要放在Assets/Editor的目录下using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NUnit.Framework.Constraints;
using UnityEditor;
using UnityEngine;
using LitJson;

public class BuildAssetsBundle : Editor
{
    private const string BuildAssetsBundleMenuAll = "Tools/BuildAssetsBundle";
    private const string BuildAssetsBundleMenu = "Assets/BuildAssetsBundle";
    private static List<string> assetNames = new List<string>();
    /// <summary>
    /// 打包assetsbundle的源文件的文件夹
    /// </summary>
    private static string OriginalDirectory = Application.dataPath + "/Resources/";
    /// <summary>
    /// 打出包的输出文件夹
    /// </summary>
    private static string OutDirectory = "Assets/StreamingAssets/AssetsBundle/";
    private const string ConfigFile = "Assets/StreamingAssets/AssetsBundle/AssetsBundleConfig.Config";
    //配置文件json,对应的对象实例    
    private static AssetsBundleConfig config = null;
    #region  打assets包
    /// <summary>
    /// 打包Assets/package目录下的所有文件为bundle包
    /// </summary>
    [MenuItem(BuildAssetsBundleMenuAll)]
    public static void BuildAssetsBundleAll()
    {
        DirectoryInfo info = new DirectoryInfo(OriginalDirectory);
        DirectoryInfo[] infos = info.GetDirectories();
        GetConfig();
        for (int i = 0; i < infos.Length; i++)
        {
            var name = infos[i].Name;
            FindAllFile(OriginalDirectory + name + "/", name);
        }
        OutPutConfig();
    }
    //根据具体文件夹打包assetsbundle
    [MenuItem(BuildAssetsBundleMenu, false, 1)]
    public static void BuildAssetsB()
    {
        var paths = Selection.assetGUIDs.Select(AssetDatabase.GUIDToAssetPath).Where(AssetDatabase.IsValidFolder).ToList();
        if (paths.Count > 1)
        {
            EditorUtility.DisplayDialog("", "不能同时选择多个目录进行该操作!", "确定");
            return;
        }
        var strName = paths[0].Split('/');
        GetConfig();
        FindAllFile(paths[0], strName[strName.Length - 1]);
        OutPutConfig();
    }
    static void FindAllFile(string path, string assetsBundlename)
    {
        assetNames.Clear();
        FindFile(path);
        CreateAssetBunlde(assetsBundlename);
    }
    static void FindFile(string assetBundleName)
    {
        DirectoryInfo di = new DirectoryInfo(assetBundleName);

        FileInfo[] fis = di.GetFiles();
        for (int i = 0; i < fis.Length; i++)
        {
            if (fis[i].Extension != ".meta")
            {
                string str = fis[i].FullName;
                assetNames.Add(str.Substring(str.LastIndexOf("Assets")));
            }
        }
        DirectoryInfo[] dis = di.GetDirectories();
        for (int j = 0; j < dis.Length; j++)
        {
            FindFile(dis[j].FullName);
        }
    }
    /// <summary>
    /// 每次打包assetsbundle的前要获取整个配置文件
    /// </summary>
    static void GetConfig()
    {
        config = null;
        var bytes = FileTools.TryReadFile(ConfigFile);
        config = (bytes == null) ? new AssetsBundleConfig() : JsonMapper.ToObject<AssetsBundleConfig>(Encoding.UTF8.GetString(bytes));
    }
    /// <summary>
    /// 打包好了,要输出配置文件
    /// </summary>
    static void OutPutConfig()
    {
        if (config != null && config.AssetsBundles != null & config.AssetsBundles.Count > 0)
        {
            var content = JsonMapper.ToJson(config);
            FileTools.TryWriteFile(ConfigFile, content);
        }
        AssetDatabase.Refresh();
    }
    /// <summary>
    /// 打包资源到StreamingAssets下对应的平台,对应的资源名
    /// </summary>
    /// <param name="assetBundleName"></param>
    static void CreateAssetBunlde(string assetBundleName)
    {
        string[] assetBundleNames = assetNames.ToArray();
        AssetBundleBuild[] abs = new AssetBundleBuild[1];
        abs[0].assetNames = assetBundleNames;
        abs[0].assetBundleName = assetBundleName + ".assetBundle";
        BuildTarget buildTarget;
        string outPutPlat;
#if UNITY_ANDROID   //安卓  
        buildTarget = BuildTarget.Android;
        outPutPlat = "Android";
#elif UNITY_IOS
        buildTarget = BuildTarget.iOS;
        outPutPlat = "IOS";
#else
        buildTarget = BuildTarget.StandaloneWindows;
        outPutPlat = "Windows";
#endif
        var dicName = OutDirectory + outPutPlat;
        FileTools.EnsureDirectoryExist(dicName);
        AssetBundleManifest mainfest = BuildPipeline.BuildAssetBundles(dicName, abs, BuildAssetBundleOptions.None, buildTarget);
        var filepath = dicName + "/" + abs[0].assetBundleName;
        var size = (int)FileTools.TryGetFileSize(filepath);
        var assets = CreateAssets(assetBundleName, outPutPlat, size);
        if (config.AssetsBundles != null && config.AssetsBundles.Count > 0)
        {
            for (int i = 0; i < config.AssetsBundles.Count; i++)
            {
                var havedAssets = config.AssetsBundles[i];
                if ((havedAssets.name == assets.name) && (havedAssets.platform == assets.platform))
                {
                    config.AssetsBundles.Remove(havedAssets);
                    break;
                }
            }
        }
        config.AssetsBundles.Add(assets);
        Debug.LogError(assetBundleName + "打包完成");
    }
    /// <summary>
    /// 新建assetbundle对应的对象实例
    /// </summary>
    /// <param name="assetBundleName"></param>
    /// <param name="platform"></param>
    /// <returns></returns>
    static Assets CreateAssets(string assetBundleName, string platform,int size)
    {
        Assets assets = new Assets();
        assets.name = assetBundleName;
        assets.platform = platform;
        assets.size = size;
        return assets;
    }
    #endregion
}
assetsbundle的实体配置类using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// AssetsBundleConfig配置文件的映射对象
/// </summary>
[SerializeField]
public class AssetsBundleConfig
{
    [SerializeField]
    public List<Assets> AssetsBundles;
    public AssetsBundleConfig()
    {
        AssetsBundles = new List<Assets>();
    }
}
[SerializeField]
public class Assets
{
    /// <summary>
    /// AssetsBundle的名字
    /// </summary>
    [SerializeField]
    public string name;
    /// <summary>
    /// AssetsBundle的大小
    /// </summary>
    [SerializeField]
    public int size;
    /// <summary>
    /// AssetsBundle的所属平台0-window,1-ios,2-android
    /// </summary>
    [SerializeField]
    public string platform;

    public Assets()
    {
    }

    public Assets(string name, int size, string platform)
    {
        this.name = name;
        this.size = size;
        this.platform = platform;
    }
}


操作文件的工具类

  转自:https://blog.csdn.net/qq_22911163/article/details/79097462

unity资源管理热更必备

上一篇讲到了如何打包assetsbundle,紧跟而来的就是加载assetsbundle的问题。资源的动态的加载用到Resources和AssetsBundle这两种方式,而后一种方式无论是在热更还是大小,安全等方面更具优势。下面要贴出作者一直在用的资源管理方式。大概是利用枚举区分这两种方式,在unity编辑器里可以随意切换,打包发布时也可以根据自己的需求切换。利用assetsbundle加载资源时,需要在启动游戏的时候,将所需的assetsbundle加载进内存,再通过具体方法加载assets bundle的资源。这里我设置了一个最大资源加载数的选项, 因为游戏要加载的,动态生成的prefab等往往不会频繁使用,通过queue队列的方式,可以有效减少动态加载量很少的资源,常驻内存的情况。废话不多说了,贴两张效果图下面贴一下代码using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;
using LitJson;
using System.Linq;

enum LoadAssetsType
{
    AssetsBundle = 0,
    Resources = 1
}


public class AssetsManager : MonoBehaviour
{
    /// <summary>
    /// 单例
    /// </summary>
    private static AssetsManager _instance;
    [SerializeField]
    [Tooltip("加载资源的方式")]
    private LoadAssetsType _loadAssetsType;
    [SerializeField]
    [Tooltip("最大资源缓存数")]
    private int _maxResourcesCount = 30;
    /// <summary>
    /// 数据字典
    /// </summary>
    private Dictionary<string, Object> _dicAssets = new Dictionary<string, Object>();
    /// <summary>
    /// 资源key值的队列
    /// </summary>
    private Queue<string> _assetsName = new Queue<string>();
    /// <summary>
    /// AssetBundle字典集合
    /// </summary>
    private Dictionary<string, AssetBundle> _dicAssetBundles = new Dictionary<string, AssetBundle>();
    private List<Assets> _AssetsList = new List<Assets>();
    //不同平台下StreamingAssets的路径是不同的,这里需要注意一下。 
    private static string _streamingAssetsPath;
    private static string _resourcesPath;
    //配置文件的路径
    private static string _configPath;
    private void Awake()
    {
        SetResourcesPath();
        StartCoroutine(Initassetsbundle());
    }
    private static void SetResourcesPath()
    {
        _streamingAssetsPath =
#if UNITY_ANDROID 
        "jar:file://" + Application.dataPath + "!/assets/AssetsBundle/";
#elif UNITY_IOS 
        Application.dataPath + "/Raw/AssetsBundle/";  
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
            "file://" + Application.dataPath + "/StreamingAssets/AssetsBundle/";
#else
        string.Empty;  
#endif
        if (Application.platform == RuntimePlatform.Android)
        {
            _resourcesPath = _streamingAssetsPath + "Android/";
        }
        else if (Application.platform == RuntimePlatform.IPhonePlayer)
        {
            _resourcesPath = _streamingAssetsPath + "IOS/";
        }
        else
        {
            _resourcesPath = _streamingAssetsPath + "Windows/";
        }
        _configPath = _streamingAssetsPath + "AssetsBundleConfig.Config";
    }
    /// <summary>
    /// 单例
    /// </summary>
    /// <returns></returns>
    public static AssetsManager GetInstance()
    {
        if (_instance == null)
        {
            var go = GameObject.Find("game");
            if (go == null)
            {
                go = new GameObject("game");
            }
            var assetsManager = go.GetComponent<AssetsManager>();
            if (assetsManager == null)
            {
                assetsManager = go.AddComponent<AssetsManager>();
            }
            _instance = assetsManager;
            if (string.IsNullOrEmpty(_resourcesPath))
            {
                SetResourcesPath();
            }
        }
        return _instance;
    }
    /// <summary>
    /// 初始化assetsbundle
    /// </summary>
    /// <returns></returns>
    IEnumerator Initassetsbundle()
    {
        WWW w = new WWW(_configPath);
        yield return w;
        string content = null;
        if (string.IsNullOrEmpty(w.error))
        {
            content = w.text;
        }
        else
        {
            yield break;
        }
        _AssetsList.Clear();
        var config = JsonMapper.ToObject<AssetsBundleConfig>(content);
        //判断平台,只加载相应平台的assetbundle
        for (int i = 0; i < config.AssetsBundles.Count; i++)
        {
            string outPutPlat;
#if UNITY_ANDROID   
        outPutPlat = "Android";
#elif UNITY_IOS
        outPutPlat = "IOS";
#else
            outPutPlat = "Windows";
#endif
            var assets = config.AssetsBundles[i];
            if (assets.platform == outPutPlat)
            {
                _AssetsList.Add(assets);
            }
        }
        _AssetsList.Reverse();
        LoadAllAssetsBundle();
    }
    /// <summary>
    /// 加载所有assetsbundle进字典
    /// </summary>
    private void LoadAllAssetsBundle()
    {
        if (_AssetsList != null && _AssetsList.Count > 0)
        {
            _AssetsList.ForEach((m) =>
            {
                StartCoroutine(LoadOneAssetsBundle(m));
            });
        }
    }
    /// <summary>
    /// 加载单个assetsbundle进字典
    /// </summary>
    /// <param name="assets"></param>
    /// <returns></returns>
    IEnumerator LoadOneAssetsBundle(Assets assets)
    {
        WWW www = new WWW(_resourcesPath + assets.name + ".assetbundle");
        yield return www;
        if (string.IsNullOrEmpty(www.error))
        {
            var asset = www.assetBundle;
            _dicAssetBundles.Add(assets.name, asset);
            float p = ((float)_dicAssetBundles.Count / _AssetsList.Count);
            //是否加载完了所有的assetsbundle,TODO 通知游戏启动项,为了完成demo,先这样写
            if (p==1)
            {
                GameObject.Find("game").AddComponent<Test>();
            }
        }
    }
    public T LoadAssets<T>(string path) where T : Object
    {
        if (string.IsNullOrEmpty(path))
        {
            Debug.LogError("传进的路径不合法");
            return null;
        }
        string[] paths = null;
        if (_dicAssets.ContainsKey(path))
        {
            return (T)_dicAssets[path];
        }
        switch (_loadAssetsType)
        {
            case LoadAssetsType.AssetsBundle:
                paths = path.Split('/');
                path = paths[paths.Length - 1];
                return AssetsBundleLoad<T>(path);
            case LoadAssetsType.Resources:
                paths = path.Split('.');
                path = paths[0];
                return ResourcesLoad<T>(path);
            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    private T AssetsBundleLoad<T>(string path) where T : Object
    {
        foreach (var key in _dicAssetBundles.Keys)
        {
            var a = _dicAssetBundles[key];
            var data = (T)a.LoadAsset(path, typeof(T));
            if (data != null)
            {
                AddResouce(path, data);
                return data;
            }
        }
        Debug.LogError("根据这个路径什么都没有找到" + path);
        return null;
    }
    private T ResourcesLoad<T>(string path) where T : Object
    {
        var data = Resources.Load<T>(path);
        if (data != null)
        {
            AddResouce(path, data);
        }
        else
        {
            Debug.LogError("根据这个路径什么都没有找到" + path);
        }
        return data;
    }
    /// <summary>
    /// 往字典里添加资源
    /// </summary>
    /// <param name="path"></param>
    /// <param name="obj"></param>
    private void AddResouce(string path, Object obj)
    {
        if (_dicAssets.Count >= _maxResourcesCount)
        {
            var lastResourceName = _assetsName.Dequeue();
            _dicAssets.Remove(lastResourceName);
        }
        _assetsName.Enqueue(path);
        _dicAssets.Add(path, obj);
    }
}
这里加载assetsbundle需要根据上次打包生成的json配置文件,去读到具体的assetbundle,然后加载,很好的支持了热更todo这里,需要用事件机制告诉其他组件,已经准备好了assetsbundle。下节讲解事件机制吧,敬请期待。using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour {

    void Start () {
        //加载资源,参数需要这样传,Resources下面的第一个目录开始,需要后缀结尾
        var cube = AssetsManager.GetInstance().LoadAssets<GameObject>("view/ui.prefab");
        Debug.LogError(cube.name);
    }
}

---------------------

本文来自 苏江水 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/qq_22911163/article/details/79106692?utm_source=copy 

猜你喜欢

转载自blog.csdn.net/qq_31967569/article/details/82850817
今日推荐