效果图:
未更新前的:
重新启动后:
更新下载:
1.先成功运行框架中的例子
2.分析GameManager中的IEnumerator OnUpdateResource(),发现它向服务器发送的第一条信息为:http://localhost:6688/files.txt?v=当前时间,这条信息到达服务器后,会由HttpServer中的OnGetRequest进行处理,首先这条信息会被截去http://localhost:6688/和?v=当前时间,剩下files.txt,然后会在Server的同级目录下找Assets/StreamingAssets下找files.txt,如果找到就会发送给客户端。客户端得到这个从服务器下来的最新files.txt,就会进行MD5值的比较,下载变化了的内容
3.将原有的StreamingAssets进行备份,修改项目中的资源,重新生成,在服务器那建一个Assets文件夹,再将新的StreamingAssets放进去,还原旧的StreamingAssets
4.运行例子,如无意外例子是没有变化的,然后设置AppConst.UpdateMode为true,同时修改ResourceManager中的Initialize方法:m_BaseDownloadingURL = "file:///" + Util.DataPath;,然后启动服务器,然后运行例子,就会发现真的更新了!
分析一下框架自带例子,会发现它是先更新资源,然后才进行lua逻辑,展示界面。而很多情况下,我们是先展示主界面(即选择服务器及显示下载进度的那个界面),然后才更新资源的,这里我总结一下:
1.解包
2.更新lua脚本(自动更新)
3.显示主界面
4.更新其他资源(以进度条的方式进行显示)
在游戏中,UI相关的东西最好都由lua负责,当然主界面也是这样的,这样主界面就可以不断地变化了。这里为什么不是显示主界面后再把变更的资源进行统一下载呢?因为如果你要显示主界面,就需要先加载lua的一些核心脚本,那么如果你的这些核心lua脚本发生了变化,当进行更新时,你原来的核心脚本就会被删掉,从服务器那下载最新的,这时因为游戏还是需要依赖于旧的核心lua脚本,但被删除了,就会出错。因此,为了更加灵活,我觉得还是先更新lua脚本比较好。
当然,将第二第三步交换我是测试过的,容易出错。核心脚本一般会封装得很好,不会出现什么变化,而我这里指的是,客户端和服务端的files.txt中,两者的核心lua脚本的MD5值不同而导致核心lua脚本被更新(核心脚本的内容没改,但同样的脚本MD5值不同)。例如,你生成了一份新的StreamingAssets放到了服务器端,然后为了测试客户端能否下载新内容,还原了旧的StreamingAssets,此时核心脚本的MD5值就变了。
一.lua
1.创建lua模板
88-ToLua# Panel Script-Panel.lua.txt
#SCRIPTNAME# = {}; local this = #SCRIPTNAME#; local gameObject; local transform; --由LuaBehaviour自动调用 function #SCRIPTNAME#.Awake(obj) gameObject = obj; transform = obj.transform; --this.gridText = transform:FindChild('ScrollView/Grid'):GetComponent('Text'); end --由LuaBehaviour自动调用 function #SCRIPTNAME#.Start() end
require "Common/define" #SCRIPTNAME# = {}; local this = #SCRIPTNAME#; local gameObject; local transform; function #SCRIPTNAME#.New() return this; end function #SCRIPTNAME#.Awake() panelMgr:CreatePanel('Prompt', this.OnCreate);--需修改处 end function #SCRIPTNAME#.OnCreate(obj) gameObject = obj; transform = obj.transform; --go.transform.localPosition = Vector3.zero; end
2.封装一个事件中心
框架提供了一个events.lua,可以对它进行再一次封装,这样c#发送事件给lua也很方便:
EventType = { --这几个是和NotiConst.cs对应的 UPDATE_PROGRESS = "UpdateProgress", --更新进度 UPDATE_DOWNLOAD = "UpdateDownload", --更新下载,下载完一个文件就会被发送 UPDATE_ALLCOUNT = "UpdateAllCount", --更新文件数 }
Event = require 'events' EventCenter = {}; local Events = {}; function EventCenter.AddListener(eventType, func) Events[eventType] = true; Event.AddListener(eventType, func); end function EventCenter.RemoveListener(eventType, func) Events[eventType] = false; Event.RemoveListener(eventType, func); end function EventCenter.Brocast(eventType, ...) if Events[eventType] then Event.Brocast(eventType, ...); end end
二.c#(主要是对GameManager和AppView进行了变动)
注意点:
AppView
1.一般情况下,c#调用lua使用的是Util.CallMethod,如果这个方法在子线程中被调用,那么就会报get_xxx can only be called from the main thread的错误,那么可以将调用转移到Awake、Start和Update等mono的方法
2.很多时候,我们需要获取下载进度,并把它展示出来,那么通过ThreadManager中的ProgressChanged,它会把消息进行分发,其中AppView会对NotiConst.UPDATE_PROGRESS进行监听,执行对应的方法。
3.由于框架使用的是ThreadManager进行线程下载,所以下载进度、是否下载完成等信息是不能与界面显示同步的。
GameManager
就是上面所说的四个步骤了
工程下载:
http://pan.baidu.com/s/1nvrgM97