Unity资源目录
当用Unity创建一个工程的时候,目录如下:
Assets:存放Unity工程实际的资源目录。
Library:存放Unity处理完毕的资源,由unity自动转化生成。
Log:存放日志文件。
Packages:统一管理各种packages组件,使用PackageManager进行管理。
ProjectSettings:存放Unity的各种项目设定。
当进行项目迁移时,只需要将Assets、Packages以及ProjectSettings三个目录拷贝即可。
Unity提供了Resource加载和AssetBundle加载两种方式
引用这篇文章的内容 Unity资源管理(二)-Resources文件夹
强烈不建议使用Resources系统,原因如下:
使用Resources文件夹将会使细粒度的内存管理变得更难
对Resources文件夹的不恰当使用会导致应用程序构架和启动时间变长
随着Resources文件夹数量的增加,在这些文件夹中管理Asset将会变得越来越难
使用Resources系统会降低项目向不同平台提供定制内容的能立,并且导致项目无法进行增量内容更新
AssetBundle学习
AssetBundle 官方API文档
AssetBundles的压缩方式:LZMA、LZ4、不压缩
1. 加载AssetBundles
AssetBundle.LoadFromMemory(Async optional) // 不推荐,此API会消耗两倍于AB大小的内存
AssetBundle.LoadFromFile(Async optional) // 推荐使用
UnityWebRequest.GetAssetBundle // 在Unity 5.2及更早版本中使用 WWW.LoadFromCacheOrDownload
2. 从AssetBundles中加载Assets
LoadAsset(LoadAssetAsync) // 加载单个或者少量时使用
LoadAllAssets(LoadAllAssetsAsync) // 加载多数或者所有Assets时使用
LoadAssetWithSubAssets(LoadAssetWithSubAssetsAsync)
3. 构建AssetBundls管线
BuildPipeline.BuildAssetBundles
4. 卸载不使用的AssetBundls
AssetBundle.unload(true) // false会有引用丢失的风险
tips:开发一个良好的分离下载系统是至关重要的
自动打包至指定文件夹
- 自动添加label
using UnityEngine;
using UnityEditor;
using System.IO;namespace ABFW
{public class AutoSetLabels{[MenuItem("AssetBundleTools/Set AB Label")]public static void SetABLable(){// 清空标记AssetDatabase.RemoveUnusedAssetBundleNames();// AB根目录 调用文件ABPath.cs统一获取路径string strNeedSetlabelRoot = ABPath.GetABResourcesPath();// 通过根路径获取目录DirectoryInfo dirTempInfo = new DirectoryInfo(strNeedSetlabelRoot);DirectoryInfo[] dirSceneDirArray = dirTempInfo.GetDirectories();// 遍历所有路径foreach (DirectoryInfo currentDIR in dirSceneDirArray){Debug.Log("输出目录所有" + currentDIR);string tmpScenesDIR = strNeedSetlabelRoot + "/" + currentDIR.Name;int tmpIndex = tmpScenesDIR.LastIndexOf("/");string tmpScenesName = tmpScenesDIR.Substring(tmpIndex + 1);JudgeDIRorFileByRecursive(currentDIR, tmpScenesName);}// 刷新列表AssetDatabase.Refresh();Debug.Log("-----------------AB初始化完成--------------------");}/// <summary>/// 递归判断是否为目录/文件,修改AssetBundle/// </summary>/// <param name="fileSysInfo">目录信息</param>/// <param name="scenesName">场景名称</param>private static void JudgeDIRorFileByRecursive(FileSystemInfo fileSysInfo, string scenesName){if (!fileSysInfo.Exists){Debug.Log("文件或者目录名称:" + fileSysInfo + "不存在,请检查");return;}DirectoryInfo dirInfoObj = fileSysInfo as DirectoryInfo;FileSystemInfo[] fileSysArray = dirInfoObj.GetFileSystemInfos();// 遍历文件 设置标签foreach (FileSystemInfo fileInfo in fileSysArray){FileInfo fileInfoObj = fileInfo as FileInfo;if (fileInfoObj != null){// 文件类型 设置lableSetFilesABLabel(fileInfoObj, scenesName);}else{// 目录文件 递归JudgeDIRorFileByRecursive(fileInfo, scenesName);}}}/// <summary>/// 设置AB标签/// </summary>/// <param name="fileInfoObj">文件信息</param>/// <param name="scenesName">场景名称</param>private static void SetFilesABLabel(FileInfo fileInfoObj, string scenesName){if (fileInfoObj.Extension == ".meta") return;// AB名string strABName = GetABName(fileInfoObj, scenesName);// 获取文件的相对路径,从Assets/开始int tmpIndex = fileInfoObj.FullName.IndexOf("Assets");string strAssetFilepath = fileInfoObj.FullName.Substring(tmpIndex);AssetImporter tmpImporterObj = AssetImporter.GetAtPath(strAssetFilepath);// 设置AB名tmpImporterObj.assetBundleName = strABName;// 根据拓展名设置AB后缀if (fileInfoObj.Extension == ".unity"){tmpImporterObj.assetBundleVariant = "u3d";} else{tmpImporterObj.assetBundleVariant = "ab";}}/// <summary>/// 获取AB包的名称/// </summary>/// <param name="fileInfoObj"></param>/// <param name="scenesName"></param>/// <returns></returns>private static string GetABName(FileInfo fileInfoObj, string scenesName){string tmpWinPath = fileInfoObj.FullName;string tmpUnityPath = tmpWinPath.Replace("\\", "/");// 场景名称后面的字符数int tmpSceneNameposition = tmpUnityPath.IndexOf(scenesName) + scenesName.Length;// 拓展名区域string strABFileNameArea = tmpUnityPath.Substring(tmpSceneNameposition + 1);string strABName;if (strABFileNameArea.Contains("/")){string[] tmpStrArray = strABFileNameArea.Split('/');strABName = scenesName + "/" + tmpStrArray[0];}else{strABName = scenesName + "/" + scenesName;}return strABName;}}
}
- 根据label进行打包
using System.IO;
using UnityEditor;
using UnityEngine;namespace ABFW
{public class BuildAssetsBundle{[MenuItem("AssetBundleTools/Build All AB")]public static void BuildAllAB(){// 创建目录string strABOutPathDIR = ABPath.GetABOutPath();if (!Directory.Exists(strABOutPathDIR)){Directory.CreateDirectory(strABOutPathDIR);}// 调用内置API打包BuildPipeline.BuildAssetBundles(strABOutPathDIR, BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);}}}
- 删除所有的AB包
using System.IO;
using UnityEditor;
using UnityEngine;namespace ABFW
{public class DeleteAssetsBundle : MonoBehaviour{[MenuItem("AssetBundleTools/Delete All AB")]public static void DeleteAllBundle(){string strNeedDeleteDIR = ABPath.GetABOutPath();if (!string.IsNullOrEmpty(strNeedDeleteDIR)){Directory.Delete(strNeedDeleteDIR, true);File.Delete(strNeedDeleteDIR + ".meta ");AssetDatabase.Refresh();} else{Debug.LogError("无可删除的AB文件");}}}
}
生成MD5校验文件
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using ABFW;namespace HotUpdateModel
{public class CreateVerifyFiles{[MenuItem("AssetBundleTools/Create Verify Files")]public static void CreateFileMethod(){string abOutPath = ABPath.GetABOutPath();string verifyOutPath = abOutPath + "/ProjectVerifyFile.txt";List<string> fileList = new List<string>();if (File.Exists(verifyOutPath)){File.Delete(verifyOutPath);}ListFiles(new DirectoryInfo(abOutPath), ref fileList);WriteVerifyFile(verifyOutPath, fileList);}private static void ListFiles(FileSystemInfo fileSystemInfo, ref List<string> fileList){DirectoryInfo dirInfo = fileSystemInfo as DirectoryInfo;FileSystemInfo[] fileSysInfo = dirInfo.GetFileSystemInfos();foreach (FileSystemInfo item in fileSysInfo){FileInfo fileInfo = item as FileInfo;if (fileInfo != null){// 文件类型string strFileFullName = fileInfo.FullName.Replace("\\", "/");string fileExt = Path.GetExtension(strFileFullName);if (fileExt.EndsWith(".meta") || fileExt.EndsWith(".bak")){continue;}fileList.Add(strFileFullName);}else{// 目录类型,继续递归ListFiles(item, ref fileList);}}}/// <summary>/// 把文件名称+对应的MD5写入文件/// </summary>/// <param name="verifyFileOutPath">验证文件的路径</param>/// <param name="fileLists">所有合法文件的相对路径集合</param>private static void WriteVerifyFile(string verifyFileOutPath, List<string> fileLists){Debug.Log("verifyFileOutPath" + verifyFileOutPath);using (FileStream fs = new FileStream(verifyFileOutPath, FileMode.CreateNew)){using (StreamWriter sw = new StreamWriter(fs)){for (int i = 0; i < fileLists.Count; i++){string strFile = fileLists[i];string strFileMD5 = Helps.GetMD5Value(strFile);string strTrueFileName = strFile.Replace(ABPath.GetABOutPath() + "/", string.Empty);sw.WriteLine(strTrueFileName + "|" + strFileMD5);}}}AssetDatabase.Refresh();}}
}
拷贝Lua脚本至指定文件夹
using UnityEngine;
using UnityEditor;
using System.IO;
using ABFW;public class CopyLuaFileToStreamAssets
{private static string _LuaIRPath = Application.dataPath + "/" + ABPath.LUA_RESOURCE_PATH;private static string _CopyTargetIR = ABPath.GetABOutPath() + "/" + ABPath.LUA_DEPLOY_PATH;[MenuItem("AssetBundleTools/Copy LuaFile To StreamAssets")]public static void CopyLuaTo(){DirectoryInfo dirInfo = new DirectoryInfo(_LuaIRPath);FileInfo[] files = dirInfo.GetFiles();if (!Directory.Exists(_CopyTargetIR)){Directory.CreateDirectory(_CopyTargetIR);}// 逐个拷贝foreach (FileInfo infoObj in files){File.Copy(infoObj.FullName, _CopyTargetIR + "/" + infoObj.Name, true);}Debug.Log("---------拷贝完成,Lua文件已拷贝至发布区--------");AssetDatabase.Refresh();}
}
贴一个工具 游戏/VR应用性能诊断与优化 UWA框架