当用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 官方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:开发一个良好的分离下载系统是至关重要的
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初始化完成--------------------");
}
///
/// 递归判断是否为目录/文件,修改AssetBundle
///
/// 目录信息
/// 场景名称
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)
{
// 文件类型 设置lable
SetFilesABLabel(fileInfoObj, scenesName);
}
else
{
// 目录文件 递归
JudgeDIRorFileByRecursive(fileInfo, scenesName);
}
}
}
///
/// 设置AB标签
///
/// 文件信息
/// 场景名称
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";
}
}
///
/// 获取AB包的名称
///
///
///
///
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;
}
}
}
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);
}
}
}
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文件");
}
}
}
}
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);
}
}
}
///
/// 把文件名称+对应的MD5写入文件
///
/// 验证文件的路径
/// 所有合法文件的相对路径集合
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();
}
}
}
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框架