[Unity Asset]AssetBundle系列——游戏资源打包
转载:http://www.cnblogs.com/sifenkesi/p/3557231.html
将本地资源打包,然后放到资源服务器上供游戏客户端下载或更新。服务器上包含以下资源列表:
(1)游戏内容资源assetbundle
(2)资源维护列表,包含每个资源的名字(完整路径名)和对应的版本号[资源名,版本号],如下表所示(VersionNum.xml):
<VersionNum>
<File FileName="Assets.Resources.BigLevelTexture.TestLevel.assetbundle" Num="1" />
<File FileName="Assets.Resources.EquipmentTexture.Test001.assetbundle" Num="1" />
<File FileName="Assets.Resources.EquipmentTexture.Test002.assetbundle" Num="1" />
<File FileName="Assets.Resources.EquipmentTexture.Test003.assetbundle" Num="1" />
<File FileName="Assets.Resources.EquipmentTexture.Test004.assetbundle" Num="1" />
<File FileName="Assets.Resources.PetTexture.Empty.assetbundle" Num="1" />
</VersionNum>
那么本地客户端的资源打包编辑器就需要完成以下工作:将资源打包、生成版本号。
我们采用通过MD5码对比的方式来对版本号进行管理,如果某资源的MD5码变更了,则将其版本号+1,否则不变。那么,可以将编辑器的具体任务划分如下:
(1)将资源打包成assetbundle,并放到指定目录下
(2)为每个assetbund生成最新MD5码,用于检查资源是否有修改
(3)比较新旧MD5码列表,产生资源变更列表,对于每个变更的资源,将其版本号+1
(4)将变更列表文件也打包成assetbundle
各个平台使用的资源包时各自独立的,打包资源代码时的选项不一样,编辑器界面如下,图2中的4个按钮每个对应上述的一步操作:


最终生成的资源目录结构如下所示:

编辑器代码如下所示(包括菜单项和窗口):
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections;
using System.Collections.Generic; public class AssetBundleController : EditorWindow
{
public static AssetBundleController window;
public static UnityEditor.BuildTarget buildTarget = BuildTarget.StandaloneWindows; [MenuItem("XiYouEditor/AssetBundle/AssetBundle For Windows32", false, 1)]
public static void ExecuteWindows32()
{
if (window == null)
{
window = (AssetBundleController)GetWindow(typeof(AssetBundleController));
}
buildTarget = UnityEditor.BuildTarget.StandaloneWindows;
window.Show();
} [MenuItem("XiYouEditor/AssetBundle/AssetBundle For IPhone", false, 2)]
public static void ExecuteIPhone()
{
if (window == null)
{
window = (AssetBundleController)GetWindow(typeof(AssetBundleController));
}
buildTarget = UnityEditor.BuildTarget.iPhone;
window.Show();
} [MenuItem("XiYouEditor/AssetBundle/AssetBundle For Mac", false, 3)]
public static void ExecuteMac()
{
if (window == null)
{
window = (AssetBundleController)GetWindow(typeof(AssetBundleController));
}
buildTarget = UnityEditor.BuildTarget.StandaloneOSXUniversal;
window.Show();
} [MenuItem("XiYouEditor/AssetBundle/AssetBundle For Android", false, 4)]
public static void ExecuteAndroid()
{
if (window == null)
{
window = (AssetBundleController)GetWindow(typeof(AssetBundleController));
}
buildTarget = UnityEditor.BuildTarget.Android;
window.Show();
} [MenuItem("XiYouEditor/AssetBundle/AssetBundle For WebPlayer", false, 5)]
public static void ExecuteWebPlayer()
{
if (window == null)
{
window = (AssetBundleController)GetWindow(typeof(AssetBundleController));
}
buildTarget = UnityEditor.BuildTarget.WebPlayer;
window.Show();
} void OnGUI()
{
if (GUI.Button(new Rect(10f, 10f, 200f, 50f), "(1)CreateAssetBundle"))
{
CreateAssetBundle.Execute(buildTarget);
EditorUtility.DisplayDialog("", "Step (1) Completed", "OK");
} if (GUI.Button(new Rect(10f, 80f, 200f, 50f), "(2)Generate MD5"))
{
CreateMD5List.Execute(buildTarget);
EditorUtility.DisplayDialog("", "Step (2) Completed", "OK");
} if (GUI.Button(new Rect(10f, 150f, 200f, 50f), "(3)Compare MD5"))
{
CampareMD5ToGenerateVersionNum.Execute(buildTarget);
EditorUtility.DisplayDialog("", "Step (3) Completed", "OK");
} if (GUI.Button(new Rect(10f, 220f, 200f, 50f), "(4)Build VersionNum.xml"))
{
CreateAssetBundleForXmlVersion.Execute(buildTarget);
EditorUtility.DisplayDialog("", "Step (4) Completed", "OK");
}
} public static string GetPlatformPath(UnityEditor.BuildTarget target)
{
string SavePath = "";
switch (target)
{
case BuildTarget.StandaloneWindows:
SavePath = "Assets/AssetBundle/Windows32/";
break;
case BuildTarget.StandaloneWindows64:
SavePath = "Assets/AssetBundle/Windows64/";
break;
case BuildTarget.iPhone:
SavePath = "Assets/AssetBundle/IOS/";
break;
case BuildTarget.StandaloneOSXUniversal:
SavePath = "Assets/AssetBundle/Mac/";
break;
case BuildTarget.Android:
SavePath = "Assets/AssetBundle/Android/";
break;
case BuildTarget.WebPlayer:
SavePath = "Assets/AssetBundle/WebPlayer/";
break;
default:
SavePath = "Assets/AssetBundle/";
break;
} if (Directory.Exists(SavePath) == false)
Directory.CreateDirectory(SavePath); return SavePath;
} public static string GetPlatformName(UnityEditor.BuildTarget target)
{
string platform = "Windows32";
switch (target)
{
case BuildTarget.StandaloneWindows:
platform = "Windows32";
break;
case BuildTarget.StandaloneWindows64:
platform = "Windows64";
break;
case BuildTarget.iPhone:
platform = "IOS";
break;
case BuildTarget.StandaloneOSXUniversal:
platform = "Mac";
break;
case BuildTarget.Android:
platform = "Android";
break;
case BuildTarget.WebPlayer:
platform = "WebPlayer";
break;
default:
break;
}
return platform;
} }
(1)将资源打包成assetbundle,并放到自定目录下:
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections;
using System.Collections.Generic; public class CreateAssetBundle
{
public static void Execute(UnityEditor.BuildTarget target)
{
string SavePath = AssetBundleController.GetPlatformPath(target); // 当前选中的资源列表
foreach (Object o in Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets))
{
string path = AssetDatabase.GetAssetPath(o); // 过滤掉meta文件和文件夹
if(path.Contains(".meta") || path.Contains(".") == false)
continue; // 过滤掉UIAtlas目录下的贴图和材质(UI/Common目录下的所有资源都是UIAtlas)
if (path.Contains("UI/Common"))
{
if ((o is Texture) || (o is Material))
continue;
} path = SavePath + ConvertToAssetBundleName(path);
path = path.Substring(0, path.LastIndexOf('.'));
path += ".assetbundle"; BuildPipeline.BuildAssetBundle(o, null, path, BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.DeterministicAssetBundle, target);
} // scene目录下的资源 AssetDatabase.Refresh();
} static string ConvertToAssetBundleName(string ResName)
{
return ResName.Replace('/', '.');
} }
(2)为每个assetbund生成MD5码,用于检查资源是否有修改
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Xml;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography; public class CreateMD5List
{
public static void Execute(UnityEditor.BuildTarget target)
{
string platform = AssetBundleController.GetPlatformName(target);
Execute(platform);
AssetDatabase.Refresh();
} public static void Execute(string platform)
{
Dictionary<string, string> DicFileMD5 = new Dictionary<string, string>();
MD5CryptoServiceProvider md5Generator = new MD5CryptoServiceProvider(); string dir = System.IO.Path.Combine(Application.dataPath, "AssetBundle/" + platform);
foreach (string filePath in Directory.GetFiles(dir))
{
if (filePath.Contains(".meta") || filePath.Contains("VersionMD5") || filePath.Contains(".xml"))
continue; FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
byte[] hash = md5Generator.ComputeHash(file);
string strMD5 = System.BitConverter.ToString(hash);
file.Close(); string key = filePath.Substring(dir.Length + 1, filePath.Length - dir.Length - 1); if (DicFileMD5.ContainsKey(key) == false)
DicFileMD5.Add(key, strMD5);
else
Debug.LogWarning("<Two File has the same name> name = " + filePath);
} string savePath = System.IO.Path.Combine(Application.dataPath, "AssetBundle/") + platform + "/VersionNum";
if (Directory.Exists(savePath) == false)
Directory.CreateDirectory(savePath); // 删除前一版的old数据
if (File.Exists(savePath + "/VersionMD5-old.xml"))
{
System.IO.File.Delete(savePath + "/VersionMD5-old.xml");
} // 如果之前的版本存在,则将其名字改为VersionMD5-old.xml
if (File.Exists(savePath + "/VersionMD5.xml"))
{
System.IO.File.Move(savePath + "/VersionMD5.xml", savePath + "/VersionMD5-old.xml");
} XmlDocument XmlDoc = new XmlDocument();
XmlElement XmlRoot = XmlDoc.CreateElement("Files");
XmlDoc.AppendChild(XmlRoot);
foreach (KeyValuePair<string, string> pair in DicFileMD5)
{
XmlElement xmlElem = XmlDoc.CreateElement("File");
XmlRoot.AppendChild(xmlElem); xmlElem.SetAttribute("FileName", pair.Key);
xmlElem.SetAttribute("MD5", pair.Value);
} // 读取旧版本的MD5
Dictionary<string, string> dicOldMD5 = ReadMD5File(savePath + "/VersionMD5-old.xml");
// VersionMD5-old中有,而VersionMD5中没有的信息,手动添加到VersionMD5
foreach (KeyValuePair<string, string> pair in dicOldMD5)
{
if (DicFileMD5.ContainsKey(pair.Key) == false)
DicFileMD5.Add(pair.Key, pair.Value);
} XmlDoc.Save(savePath + "/VersionMD5.xml");
XmlDoc = null;
} static Dictionary<string, string> ReadMD5File(string fileName)
{
Dictionary<string, string> DicMD5 = new Dictionary<string, string>(); // 如果文件不存在,则直接返回
if (System.IO.File.Exists(fileName) == false)
return DicMD5; XmlDocument XmlDoc = new XmlDocument();
XmlDoc.Load(fileName);
XmlElement XmlRoot = XmlDoc.DocumentElement; foreach (XmlNode node in XmlRoot.ChildNodes)
{
if ((node is XmlElement) == false)
continue; string file = (node as XmlElement).GetAttribute("FileName");
string md5 = (node as XmlElement).GetAttribute("MD5"); if (DicMD5.ContainsKey(file) == false)
{
DicMD5.Add(file, md5);
}
} XmlRoot = null;
XmlDoc = null; return DicMD5;
} }
MD5列表如下所示:
<Files>
<File FileName="Assets.Resources.BigLevelTexture.TestLevel.assetbundle" MD5="54-00-42-38-D5-86-43-A6-57-9D-7C-09-3A-F8-6E-10" />
<File FileName="Assets.Resources.EquipmentTexture.Test001.assetbundle" MD5="A1-19-D4-04-17-94-18-61-60-99-35-25-3F-7C-39-93" />
<File FileName="Assets.Resources.EquipmentTexture.Test002.assetbundle" MD5="CF-36-DA-C8-D2-DB-CE-FD-4A-BF-31-81-A1-D1-D2-21" />
<File FileName="Assets.Resources.EquipmentTexture.Test003.assetbundle" MD5="EF-30-78-AE-F8-F4-A0-EC-5B-4E-45-3F-1E-EF-42-44" />
<File FileName="Assets.Resources.EquipmentTexture.Test004.assetbundle" MD5="3D-5D-A7-01-D2-B1-20-5F-B9-89-C5-CB-40-96-EC-89" />
<File FileName="Assets.Resources.PetTexture.Empty.assetbundle" MD5="D9-AC-54-F8-EB-AA-1C-36-8C-2B-6C-12-37-AB-3B-48" />
</Files>
(3)比较新旧MD5码,生成资源变更列表
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Xml;
using System.Collections;
using System.Collections.Generic; public class CampareMD5ToGenerateVersionNum
{
public static void Execute(UnityEditor.BuildTarget target)
{
string platform = AssetBundleController.GetPlatformName(target);
Execute(platform);
AssetDatabase.Refresh();
} // 对比对应版本目录下的VersionMD5和VersionMD5-old,得到最新的版本号文件VersionNum.xml
public static void Execute(string platform)
{
// 读取新旧MD5列表
string newVersionMD5 = System.IO.Path.Combine(Application.dataPath, "AssetBundle/" + platform + "/VersionNum/VersionMD5.xml");
string oldVersionMD5 = System.IO.Path.Combine(Application.dataPath, "AssetBundle/" + platform + "/VersionNum/VersionMD5-old.xml"); Dictionary<string, string> dicNewMD5Info = ReadMD5File(newVersionMD5);
Dictionary<string, string> dicOldMD5Info = ReadMD5File(oldVersionMD5); // 读取版本号记录文件VersinNum.xml
string oldVersionNum = System.IO.Path.Combine(Application.dataPath, "AssetBundle/" + platform + "/VersionNum/VersionNum.xml");
Dictionary<string, int> dicVersionNumInfo = ReadVersionNumFile(oldVersionNum); // 对比新旧MD5信息,并更新版本号,即对比dicNewMD5Info&&dicOldMD5Info来更新dicVersionNumInfo
foreach (KeyValuePair<string, string> newPair in dicNewMD5Info)
{
// 旧版本中有
if (dicOldMD5Info.ContainsKey(newPair.Key))
{
// MD5一样,则不变
// MD5不一样,则+1
// 容错:如果新旧MD5都有,但是还没有版本号记录的,则直接添加新纪录,并且将版本号设为1
if (dicVersionNumInfo.ContainsKey(newPair.Key) == false)
{
dicVersionNumInfo.Add(newPair.Key, 1);
}
else if (newPair.Value != dicOldMD5Info[newPair.Key])
{
int num = dicVersionNumInfo[newPair.Key];
dicVersionNumInfo[newPair.Key] = num + 1;
}
}
else // 旧版本中没有,则添加新纪录,并=1
{
dicVersionNumInfo.Add(newPair.Key, 1);
}
}
// 不可能出现旧版本中有,而新版本中没有的情况,原因见生成MD5List的处理逻辑 // 存储最新的VersionNum.xml
SaveVersionNumFile(dicVersionNumInfo, oldVersionNum);
} static Dictionary<string, string> ReadMD5File(string fileName)
{
Dictionary<string, string> DicMD5 = new Dictionary<string, string>(); // 如果文件不存在,则直接返回
if (System.IO.File.Exists(fileName) == false)
return DicMD5; XmlDocument XmlDoc = new XmlDocument();
XmlDoc.Load(fileName);
XmlElement XmlRoot = XmlDoc.DocumentElement; foreach (XmlNode node in XmlRoot.ChildNodes)
{
if ((node is XmlElement) == false)
continue; string file = (node as XmlElement).GetAttribute("FileName");
string md5 = (node as XmlElement).GetAttribute("MD5"); if (DicMD5.ContainsKey(file) == false)
{
DicMD5.Add(file, md5);
}
} XmlRoot = null;
XmlDoc = null; return DicMD5;
} static Dictionary<string, int> ReadVersionNumFile(string fileName)
{
Dictionary<string, int> DicVersionNum = new Dictionary<string, int>(); // 如果文件不存在,则直接返回
if (System.IO.File.Exists(fileName) == false)
return DicVersionNum; XmlDocument XmlDoc = new XmlDocument();
XmlDoc.Load(fileName);
XmlElement XmlRoot = XmlDoc.DocumentElement; foreach (XmlNode node in XmlRoot.ChildNodes)
{
if ((node is XmlElement) == false)
continue; string file = (node as XmlElement).GetAttribute("FileName");
int num = XmlConvert.ToInt32((node as XmlElement).GetAttribute("Num")); if (DicVersionNum.ContainsKey(file) == false)
{
DicVersionNum.Add(file, num);
}
} XmlRoot = null;
XmlDoc = null; return DicVersionNum;
} static void SaveVersionNumFile(Dictionary<string, int> data, string savePath)
{
XmlDocument XmlDoc = new XmlDocument();
XmlElement XmlRoot = XmlDoc.CreateElement("VersionNum");
XmlDoc.AppendChild(XmlRoot); foreach (KeyValuePair<string, int> pair in data)
{
XmlElement xmlElem = XmlDoc.CreateElement("File");
XmlRoot.AppendChild(xmlElem);
xmlElem.SetAttribute("FileName", pair.Key);
xmlElem.SetAttribute("Num", XmlConvert.ToString(pair.Value));
} XmlDoc.Save(savePath);
XmlRoot = null;
XmlDoc = null;
} }
如下图所示,根据VersionMD5.xml和VersionMD5-old.xml对比产生VersionNum.xml:

(4)将变更列表文件也打包成assetbundle
也就是讲VersionNum.xml打包后供下载:
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections;
using System.Collections.Generic; public class CreateAssetBundleForXmlVersion
{
public static void Execute(UnityEditor.BuildTarget target)
{
string SavePath = AssetBundleController.GetPlatformPath(target);
Object obj = AssetDatabase.LoadAssetAtPath(SavePath + "VersionNum/VersionNum.xml", typeof(Object));
BuildPipeline.BuildAssetBundle(obj, null, SavePath + "VersionNum/VersionNum.assetbundle", BuildAssetBundleOptions.CollectDependencies | BuildAssetBundleOptions.CompleteAssets | BuildAssetBundleOptions.DeterministicAssetBundle, target); AssetDatabase.Refresh();
} static string ConvertToAssetBundleName(string ResName)
{
return ResName.Replace('/', '.');
} }
[Unity Asset]AssetBundle系列——游戏资源打包的更多相关文章
- AssetBundle系列——游戏资源打包(一)
将本地资源打包,然后放到资源服务器上供游戏客户端下载或更新.服务器上包含以下资源列表:(1)游戏内容资源assetbundle(2)资源维护列表,包含每个资源的名字(完整路径名)和对应的版本号[资源名 ...
- (转)AssetBundle系列——游戏资源打包(一)
转自:http://www.cnblogs.com/sifenkesi/p/3557231.html 将本地资源打包,然后放到资源服务器上供游戏客户端下载或更新.服务器上包含以下资源列表:(1)游戏内 ...
- AssetBundle系列——游戏资源打包(二)
本篇接着上一篇.上篇中说到的4步的代码分别如下所示: (1)将资源打包成assetbundle,并放到自定目录下 using UnityEditor; using UnityEngine; using ...
- (转)AssetBundle系列——游戏资源打包(二)
转自:http://www.cnblogs.com/sifenkesi/p/3557290.html 本篇接着上一篇.上篇中说到的4步的代码分别如下所示: (1)将资源打包成assetbundle,并 ...
- AssetBundle系列——共享资源打包/依赖资源打包
有人在之前的博客中问我有关共享资源打包的代码,其实这一块很简单,就两个函数: BuildPipeline.PushAssetDependencies():依赖资源压栈: BuildPipeline.P ...
- (转)AssetBundle系列——共享资源打包/依赖资源打包
有人在之前的博客中问我有关共享资源打包的代码,其实这一块很简单,就两个函数: BuildPipeline.PushAssetDependencies():依赖资源压栈: BuildPipeline.P ...
- AssetBundle系列——场景资源之打包(一)
本篇讲解的是3D游戏的场景资源打包方式,首先简单的分析一下场景中所包含的资源的类型. 场景资源一般包含:地表模型(或者是Unity Terrain),非实例化物体(摄像机.空气墙.光源.各种逻辑物体之 ...
- AssetBundle系列——场景资源之解包(二)
本篇接着上一篇继续和大家分享场景资源这一主题,主要包括两个方面: (1)加载场景 场景异步加载的代码比较简单,如下所示: private IEnumerator LoadLevelCoroutine( ...
- 海外开发者推荐:10个顶级2D游戏资源站
转自:http://www.gamelook.com.cn/2015/12/239038 Gamelook报道/随着手游市场的持续增长,HTML5的发展以及大型发行商的支持,2D游戏的数量变得越来越多 ...
随机推荐
- WNDCLASS 窗口类结构
Windows 的窗口总是基于窗口类来创建的,窗口类同时确定了处理窗口消息的窗口过程(回调函数). 在创建应用程序窗口之前,必须调用 RegisterClass 函数来注册窗口类.该函数只需要一个参数 ...
- html屏蔽右键、禁止复制与禁止查看源代码
<script> function doNothing(){ window.event.returnValue=false; return false; } </script> ...
- js播放器
<object?id="player"?height="64"?width="260"?classid="CLSID:6BF ...
- 转:HTML错误编号大全
HTML错误编号大全 状态行包含HTTP版本.状态代码.与状态代码对应的简短说明信息.在大多数情况下,除了Content-Type之外的所有应答头都是可选的.但Content-Type是必需的,它描述 ...
- android 5.0新特性学习--RecyclerView
在过去很多年,我们的PC或者手机设备都是采用拟物化的设计风格,IOS采用扁平化的特性,android在2014年IO大会上说采用Material Design的设计风格,显示效果不能过于生硬的转换,而 ...
- UVA 11853 Paintball ——(dfs+圆交判定)
题意:给出一个1000*1000大小的矩阵,里面有若干圆,表示障碍物,现在要找出从左边到右边的一条通路,输出入口和出口的坐标,如果有多答案,输出y值最大的答案. 分析:从与上面相连的圆开始dfs,每次 ...
- ThinkPHP3.2.3版本框架could not find driver错误
ThinkPHP3.2.3版本框架could not find driver错误 在更新ThinkPHP框架 3.2.3 时出现错误 解决方法如下: 修改php.ini文件 extension=php ...
- HDU 5889 (最短路+网络流)
Barricade Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total S ...
- ab测试 uwsgi遇到的问题
1 请求并发数目较大时,接收到的数目小于发送的数目 1.1 描述:uwsgi正常返回302跳转 ab -n 5000 -c 250 -g test.log "192.168.50.20:90 ...
- 转:web_custom_request 函数
语法:Int web_custom_request (const char *RequestName, <List of Attributes>, [EXTRARES, <List ...