1.名词解释:
资源包:点击 LuaFramework  |  Build XXX(平台名) Resource,框架会自动将自定义指定的资源打包到StreamingAssets文件夹,这个文件夹下的unity3d文件就是资源包,它是一种u3d自己的压缩格式,也被称为AssetBundle包。

资源:资源经过打包成为资源包,如果在游戏里想用资源包里的内容的话,就需要先加载资源包到内存,然后解压这个资源包,获取资源包里包含的部分资源。

2.热更新涉及文件夹

资源目录:apk文件(安卓安装文件)其实也是一种压缩格式,安装apk之后,安卓系统会为游戏自动创建一个资源目录,用来存放apk解压出来的东西。需要特别注意的一点是,资源目录里的东西是只能读不能写的,也就是说,我们不能随意地从网上下载文件替换资源目录里的资源,所以我们需要一个可读可写的目录以便我们用下载的资源替换原资源实现热更新。由于lua文件可以当作一种资源,所以lua里的代码也是可以热更新的。资源目录路径通过Util.AppContentPath()获取,安卓上大概是这样的:jar:file///data/app.com/com.XXX.XXX-1/base.apk!/assets/(root之后才能看到),用编辑器的话,是工程所在文件夹下的StreamingAssets。

数据目录:安卓创建的用来存放游戏数据用的,可以随意读写。第一次打开游戏的时候,把资源包从资源目录复制到这里,此后每次启动游戏都会比较这里的文件和网络上的资源包,如果不一样的话,就下载下来替换这里的资源包。数据目录路径通过Util.DataPath获取,安卓上大概这样data/user/0/com.XXX.XXX-1/files/mygamename/(root之后才能看到),用编辑器的话,会创建在C盘。

网络资源目录:存放游戏资源的网址,游戏开启后,程序会从网络资源地址下载一些更新的文件到数据目录。版本控制是通过files.txt实现的,里面存放着资源文件的名称和md5码。程序会先下载“网络资源地址”上的files.txt,然后与“数据目录”中文件的md5码做比较,更新有变化的文件。
 

3.热更新的三个过程:
复制资源:将“游戏资源目录”的内容复制到“数据目录中”(只有在第一次打开游戏的时候会有此过程)
GameManager.OnExtractResource
 IEnumerator OnExtractResource() {
string dataPath = Util.DataPath; //数据目录
string resPath = Util.AppContentPath(); //游戏包资源目录 if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true);
Directory.CreateDirectory(dataPath); string infile = resPath + "files.txt";
string outfile = dataPath + "files.txt";
if (File.Exists(outfile)) File.Delete(outfile); string message = "正在解包文件:>files.txt";
Debug.Log(infile);
Debug.Log(outfile);
if (Application.platform == RuntimePlatform.Android) {
WWW www = new WWW(infile);
yield return www; if (www.isDone) {
File.WriteAllBytes(outfile, www.bytes);
}
yield return ;
} else File.Copy(infile, outfile, true);
yield return new WaitForEndOfFrame(); //释放所有文件到数据目录
string[] files = File.ReadAllLines(outfile);
foreach (var file in files) {
string[] fs = file.Split('|');
infile = resPath + fs[]; //
outfile = dataPath + fs[]; message = "正在解包文件:>" + fs[];
Debug.Log("正在解包文件:>" + infile);
facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message); string dir = Path.GetDirectoryName(outfile);
if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); if (Application.platform == RuntimePlatform.Android) {
WWW www = new WWW(infile);
yield return www; if (www.isDone) {
File.WriteAllBytes(outfile, www.bytes);
}
yield return ;
} else {
if (File.Exists(outfile)) {
File.Delete(outfile);
}
File.Copy(infile, outfile, true);
}
yield return new WaitForEndOfFrame();
}
message = "解包完成!!!";
facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
yield return new WaitForSeconds(0.1f); message = string.Empty;
//释放完成,开始启动更新资源
StartCoroutine(OnUpdateResource());
}
下载资源:从网络比对下载资源
GameManager.OnUpdateResource
 IEnumerator OnUpdateResource() {
if (!AppConst.UpdateMode) {
OnResourceInited();
yield break;
}
string dataPath = Util.DataPath; //数据目录
string url = AppConst.WebUrl;
string message = string.Empty;
string random = DateTime.Now.ToString("yyyymmddhhmmss");
string listUrl = url + "files.txt?v=" + random;
Debug.LogWarning("LoadUpdate---->>>" + listUrl); WWW www = new WWW(listUrl); yield return www;
if (www.error != null) {
OnUpdateFailed(string.Empty);
yield break;
}
if (!Directory.Exists(dataPath)) {
Directory.CreateDirectory(dataPath);
}
File.WriteAllBytes(dataPath + "files.txt", www.bytes);
string filesText = www.text;
string[] files = filesText.Split('\n'); for (int i = ; i < files.Length; i++) {
if (string.IsNullOrEmpty(files[i])) continue;
string[] keyValue = files[i].Split('|');
string f = keyValue[];
string localfile = (dataPath + f).Trim();
string path = Path.GetDirectoryName(localfile);
if (!Directory.Exists(path)) {
Directory.CreateDirectory(path);
}
string fileUrl = url + f + "?v=" + random;
bool canUpdate = !File.Exists(localfile);
if (!canUpdate) {
string remoteMd5 = keyValue[].Trim();
string localMd5 = Util.md5file(localfile);
canUpdate = !remoteMd5.Equals(localMd5);
if (canUpdate) File.Delete(localfile);
}
if (canUpdate) { //本地缺少文件
Debug.Log(fileUrl);
message = "downloading>>" + fileUrl;
facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message);
/*
www = new WWW(fileUrl); yield return www;
if (www.error != null) {
OnUpdateFailed(path); //
yield break;
}
File.WriteAllBytes(localfile, www.bytes);
*/
//这里都是资源文件,用线程下载
BeginDownload(fileUrl, localfile);
while (!(IsDownOK(localfile))) { yield return new WaitForEndOfFrame(); }
}
}
yield return new WaitForEndOfFrame(); message = "更新完成!!";
facade.SendMessageCommand(NotiConst.UPDATE_MESSAGE, message); OnResourceInited();
}
加载资源:加载资源包内的资源到内存
PanelManager.CreatePanel
     public void CreatePanel(string name, LuaFunction func = null) {
string assetName = name + "Panel";
string abName = name.ToLower() + AppConst.ExtName; ResManager.LoadPrefab(abName, assetName, delegate(UnityEngine.Object[] objs) {
if (objs.Length == ) return;
// Get the asset.
GameObject prefab = objs[] as GameObject; if (Parent.FindChild(name) != null || prefab == null) {
return;
}
GameObject go = Instantiate(prefab) as GameObject;
go.name = assetName;
go.layer = LayerMask.NameToLayer("Default");
go.transform.SetParent(Parent);
go.transform.localScale = Vector3.one;
go.transform.localPosition = Vector3.zero;
go.AddComponent<LuaBehaviour>(); if (func != null) func.Call(go);
Debug.LogWarning("CreatePanel::>> " + name + " " + prefab);
});
}
 
4.可更新的loading界面
前提:
1)如果想更新,则必须把loading界面打包进资源包
2)在第一次打开游戏的时候,下载资源阶段之前,还没有loading界面的资源包,但是此刻无疑是必须显示loading的
3)生成loading界面的两种过程:
使用Resource.Load(不可热更新)
  public void CreateLoadingPanelFromResource()
{
_MemoryPoolManager_ memMgr = AppFacade.Instance.GetManager<_MemoryPoolManager_>(ManagerName._Pool_); Debug.Log("--------------------Resources加载loading--------------------------------"); memMgr.AddPrefabPoolRS("LoadingPanel", , , true, null);
// memMgr.AddPrefabPoolAB ("loading", "LoadingPanel", 1, 1, true, null); Transform loadingPanel = _MemoryPoolManager_.Spawn("LoadingPanel", true);
loadingPanel.SetParent(GameObject.Find("2DERoot/Resolution").transform);
loadingPanel.localPosition = Vector3.zero;
loadingPanel.localScale = new Vector3(, , ); _slider = loadingPanel.FindChild("LoadingSlider").GetComponent<Slider>();
_text = loadingPanel.FindChild("LoadingSlider/Text").GetComponent<Text>();
_text.gameObject.SetActive(true);
_text.transform.localPosition = Vector3.zero;
_slider.value = ;
_text.text = "准备启动游戏";
_isStartupLoading = true; KeyFrameWork.MVC.SendEvent(FWConst.E_ShowLog, "Resources load finish");
使用加载AssetBundle资源包的方式
 public IEnumerator CreateLoadingPanelFromAssetBundle()
{
string url = Util.GetRelativePath() + "loading.unity3d";
Debug.Log("--------------------AssetBundle加载Loading--------------------------------" + url); WWW www = WWW.LoadFromCacheOrDownload(url, , ); yield return www; AssetBundle bundle = www.assetBundle;
GameObject asset = bundle.LoadAsset<GameObject>("LoadingPanel");
Transform loadingPanel = Instantiate<GameObject>(asset).GetComponent<Transform>(); //memMgr.AddPrefabPoolRS("LoadingPanel", 1, 1, true, null);
//Transform loadingPanel = _MemoryPoolManager_.Spawn ("LoadingPanel", true); loadingPanel.SetParent(GameObject.Find("2DERoot/Resolution").transform);
loadingPanel.localPosition = Vector3.zero;
loadingPanel.localScale = new Vector3(, , );
loadingPanel.name = "LoadingPanel(Clone)001"; _slider = loadingPanel.FindChild("LoadingSlider").GetComponent<Slider>();
_text = loadingPanel.FindChild("LoadingSlider/Text").GetComponent<Text>();
_text.gameObject.SetActive(true);
_slider.value = ; _isStartupLoading = true; //加载loading完成后再开始lua,保证lua能顺利接管loading
AppFacade.Instance.StartUp(); //启动游戏 KeyFrameWork.MVC.SendEvent(FWConst.E_ShowLog, "AssetBundle load finish"); }
在游戏开始的时候使用判断(Directory.Exists(Util.DataPath) && Directory.Exists(Util.DataPath + "lua/") && File.Exists(Util.DataPath + "files.txt")来确定当前是否是第一次开启游戏,如果是,则使用Resource.Load,如果不是则使用加载AssetBundle资源包的方式。这里需要着重说下加载AssetBundle资源包时的顺序问题,由于ResourceManager需要Manifest关联文件(用以确定各个资源包之间的引用关系)进行初始化,所以ResourceManager初始化必在下载资源之后,而下载资源时无疑是需要显示loading的,故顺序是:加载AssetBundle资源包-》下载资源-》ResourceManager初始化。在这个顺序下,虽然ResourceManager有加载AssetBundle资源包的接口,但是不能用。而加载AssetBundle资源包是需要异步加载的,也就是说,显示loading需要1秒左右的时间(根据具体loading资源和手机硬件而定),若是需要在lua里接管loading(通过Find函数找到loading界面然后在lua里做一个引用),则必须在loading资源包加载完毕后才能执行lua接管loading的代码
 

LuaFramework热更新过程(及可更新的loading界面实现)的更多相关文章

  1. 青瓷引擎使用心得——修改引擎的loading界面

    一. 修改引擎的Loading界面之使用进度条显示1. 双击打开引擎包中的lib/qc-loading-debug.js,如下图所示: 2. 只需要修改qici.init函数即可改变loading界面 ...

  2. Cocos Creator—定制H5游戏首页loading界面

    Cocos Creator从1.0版本发布到现在也有一年多了,按理说一些常见的问题网上都有解决方案,例如"如何自定义首页加载进度条界面"这种普遍需求,应该所有人都会遇到的,因此也有 ...

  3. cocos2d-x 3.0 Loading界面实现

    这个世界每一天都在验证我们的渺小,但我们却在努力创造,不断的在这生活的画卷中留下自己的脚印.或许等到我们老去的那一天,老得不能动仅仅能靠回顾的那一天.你躺在轮椅上,不断的回顾过去.相思的痛苦忘不了,相 ...

  4. SILVERLIGHT 应急卫生模拟演练项目之loading界面实现

    第一次在博客园写文章 俺是菜鸟 有不足之处还请大佬们多多指教 第一次也不知道该写啥 俺就拿自己最近做的一个项目 来细说吧 俺们公司是做医疗卫生方面的  其中有一块涉及到应急卫生模拟演练方面 这块分到我 ...

  5. cocos2d-x游戏开发(十五)游戏加载动画loading界面

    个人原创,欢迎转载:http://blog.csdn.net/dawn_moon/article/details/11478885 这个资源加载的loading界面demo是在玩客网做逆转三国的时候随 ...

  6. 10分钟,利用canvas画一个小的loading界面

    首先利用定义下canvas得样式 <canvas width="1024" height="720" id="canvas" styl ...

  7. 手游产品经理初探(二)从营销角度看loading界面

    近期開始写产品相关的专题,准备从细节入手去思考.总结一些不为人注意的细节地方. 今天给大家分享的是游戏里面都有的loading界面. 还是从几个在Facebook上排名靠前的Casino游戏的load ...

  8. cocos2d-x游戏开发(十五)游戏载入动画loading界面

    这个资源载入的loading界面demo是在玩客网做逆转三国的时候随手写的,尽管我在那仅仅待了2个礼拜.可是也算參与了一个商业游戏项目了,学到不少东西.当时使用的cocos2d-x还是1.0版的,我用 ...

  9. JavaFX桌面应用-loading界面

    上次使用JavaFX开发了一个视频转码工具,当用户点击"启动"按钮开始转码的时候,会禁用启动按钮,防止多次启动转码. 这种处理方式对用户来说可能并是很友好,其实可以在启动转码的时弹 ...

随机推荐

  1. 给Linux系统/网络管理员准备的Nmap命令的29个实用范例

    我将用两个不同的部分来涵盖大部分NMAP的使用方法,这是nmap关键的第一部分.在下面的设置中,我使用两台已关闭防火墙的服务器来测试Nmap命令的工作情况. 192.168.0.100 – serve ...

  2. 警告: [SetContextPropertiesRule]{Context} Setting property 'source' to 'org.eclipse.jst.jee.server:JsonBlog' did not find a matching property.

    这个问题困扰很久了,逛了很多论坛,终于得以解决 我的控制台错误如下: 五月 , :: 下午 org.apache.catalina.startup.VersionLoggerListener log ...

  3. [0] C#实现WebBrowser&HTML交互

    using System;using System.ComponentModel;using System.Windows.Forms; namespace WindowsApplication5{ ...

  4. 小试牛刀JavaScript鼠标事件

    鼠标事件练习1 当鼠标点击网页某个单元格的时候,其他的单元格颜色不变,只有被点击的单元格颜色发生变化 <style type="text/css"> *{ margin ...

  5. VMware安装CentOS 提示:已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。解决方案

    安装虚拟机遇到错误: 在网上查了查资料,发现CPU支持VT技术的就能支持vmware中安装64位虚拟机. 以下是操作步骤: 1)到网上下载一个securable.exe,测试以下机器是否支持VT. l ...

  6. iOS内购图文流程(2017)

    什么是内购? 只要在iPhone App上购买的不是实物产品(也就是虚拟产品如qq币.虎牙币.电子书......) 都需要走内购流程,苹果这里面抽走三成.   使用内购需要走的流程. 1,填写协议,税 ...

  7. PHP扩展开发-1

    开发环境信息 1.基本环境信息如下: [root@localhost lib]# cat /etc/os-release NAME="CentOS Linux" VERSION=& ...

  8. jquery 封装

    (function($) { var plugName = "teamMingXi"; var teamMingXi = { open : function(type) { var ...

  9. JAVA数字求和

    设计思想:把子符串转换成数字,通过Integer.parseInt(),然后通过循环求和. 流程图:

  10. mysqlclient和PyMySQL对比

    环境:Python 3.5+, Django 1.9+ 最初用django时,搜索时发现PyMySQL的文章很多,然而在django的官方文档中python3版的mysql客户端驱动确没有提到PyMy ...