开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1532

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 1797|回复: 19

[碧俐千仞] Unity3D热更新LuaFramework入门实战(2) 资源热更新

[复制链接]  [移动端链接]
排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

发表于 2016-7-16 21:27:35 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
本帖最后由 tyxxxx 于 2016-7-16 21:29 编辑

热更新LuaFramework入门实战
第二篇:资源热更新

热更新涉及资源热更新和代码热更新(其实lua代码也是资源),那接下来看看如何动态加载一个模型,然后热更成其他素材。这一部分涉及资源打包、动态创建资源等内容。


知乎@罗培羽


1、创建物体


为了调试的方便,笔者先将框架配置为本地模式,待测试热更新时再改成更新模式。
Unity3D热更新LuaFramework入门实战2191.png

图:配置为本地模式

先测试个简单的创建物体,新建一个名为go的物体,然后设置它的坐标为(1,1,1)。这段代码虽然不涉及资源加载,但能展示“把物体添加到场景中”的过程。Main.lua的代码如下:


[C#] 纯文本查看 复制代码
function Main()                                        
        local go = UnityEngine.GameObject ('go')
        go.transform.position = Vector3.one                
end



Unity3D热更新LuaFramework入门实战2401.png

图:动态创建一个名为go的空物体

要热更新资源,便需要制作资源。这里制作一个名为tankPrefab的坦克模型预设,然后存到Assets/Tank目录下。接下来对它做打包,然后动态加载。
Unity3D热更新LuaFramework入门实战2498.png


广告时间:这个坦克模型是来自笔者即将出版的一本书《Unity3D网络游戏实战》。该书通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。相信透过本书,读者能够掌握Unity3D网络游戏开发的大部分知识,也能够从框架设计中了解商业游戏的设计思路,感谢大家支持。


2、资源打包
LuaFramework在打包方面并没有做太多的工作,我们需要手动打包。打开Assets/LuaFramework/Editor/Packager.cs,按照示例的写法,加上下面这一行:将Assets/Tank目录下的所有预设(.prefab)打包成名为tank的包。


Unity3D热更新LuaFramework入门实战2817.png
图:修改打包代码

点击“Build Windows Resource”,即可在StreamingAssets中看到打包好的文件。

Unity3D热更新LuaFramework入门实战2885.png

图:坦克资源的包文件

如下图所示,Unity3D资源包里面包含多个资源,就像一个压缩文件一样。在动态加载的时候,便需要有加载包文件、或取包中的资源两步操作(框架已经帮我们做好了这部分工作,直接调用API即可)。
Unity3D热更新LuaFramework入门实战2994.png

图:Unity3D的资源包

3、动态加载模型

编写如下lua代码(main.lua),使用框架提供的资源管理器(resMgr)加载tank包的TankPrefab文件,加载完成后回调OnLoadFinish方法。在OnLoadFinish中使用Instantiate实例化对象。
--主入口函数。从这里开始lua逻辑


[C#] 纯文本查看 复制代码
function Main()                                        
        LuaHelper = LuaFramework.LuaHelper;
        resMgr = LuaHelper.GetResManager();
        resMgr:LoadPrefab('tank', { 'TankPrefab' }, OnLoadFinish);
end
--加载完成后的回调--
function OnLoadFinish(objs)
        local go = UnityEngine.GameObject.Instantiate(objs[0]);
        LuaFramework.Util.Log("Finish");        
end


完成后运行游戏,即可看到动态加载出来的模型。

Unity3D热更新LuaFramework入门实战21476.png

图:动态加载出来的模型

4、加载资源的过程

只有理解了动态加载,即LoadPrefab的过程,才能算是真正的理解了热更新。LoadPrefab为ResourceManager中定义的方法,在Assets\LuaFramework\Scripts\Manager\ResourceManager.cs中实现,建议配合代码看下面的解释。
LoadPrefab的流程如下所示,先是判定当前是否正在加载该资源包,如果没有则调用OnLoadAsset加载资源包、然后解包获取资源、调用回调函数。

Unity3D热更新LuaFramework入门实战21722.png

图:LoadPrefab的流程

ResourceManager类定义了m_AssetBundleManifest、m_Dependencies、m_LoadedAssetBundles、m_LoadRequests这4个变量,只要理解了这几个变量的用途,也就能够理解了资源加载的全过程了。这4个变量的类型如下:

Unity3D热更新LuaFramework入门实战21881.png

图:ResourceManager定义的几个变量

m_AssetBundleManifest

理解m_AssetBundleManifest之前,需要先理解Unity3D的依赖打包。前面的tank.中,坦克的预设、坦克的贴图等资源都被打包到一起,没有依赖关系(只要打包时不给贴图单独打包,Unity3D会自动将预设相关的资源都打包进来)。如下图所示。

Unity3D热更新LuaFramework入门实战22067.png

图:前面加载坦克制作的资源包

假如有两个坦克预设共用一套贴图,如果像上面那样打包,每个坦克预设各自包含一份贴图,资源会比较大。更好的办法是将公共贴图放到一个包里,每个坦克预设不再包含贴图(如下图)。这种打包方式下,加载TankPrefab前,需要先加载依赖包common.unity3D,坦克预设才能找到贴图。

Unity3D热更新LuaFramework入门实战22226.png

图:依赖打包

打包后,Unity3D会产生一个名为AssetBundle.manifest的文件(框架会将该文件放在StreamingAssets中),该文件包含所有包的依赖信息。所以在加载资源前需要先加载这个文件,m_AssetBundleManifest便是指向这个包的变量。相关代码如下:

Unity3D热更新LuaFramework入门实战22377.png

图:m_AssetBundleManifest便是指向AssetBundle.manifest的变量

加载这个包后,便可以使用下面的语句获取某个包所依赖的所有包名,然后加载它们。
string[] dependencies = m_AssetBundleManifest.GetAllDependencies(包名);

注:更多Unity3D的依赖打包的解释,可以参见这篇文章:
http://liweizhaolili.blog.163.com/blog/static/16230744201541410275298/

m_LoadedAssetBundles

字典类型的m_LoadedAssetBundles保存了所有已经加载资源包。如果某个包已经被加载过,那下次需要用到它时,直接从字典中取出即可,减少重复加载。简化后的代码如下:

[C#] 纯文本查看 复制代码
IEnumerator OnLoadAsset(XXX)
{
      AssetBundleInfo bundle = GetLoadedAssetBundle(XXX);  
      if(!bundle)
            bundle  =  OnLoadAssetBundle(名字);  
      加载资源
      回调函数处理
}

其中GetLoadedAssetBundle方法会判断资源包是否存在于m_LoadedAssetBundles中,并返回资源包。OnLoadAssetBundle为重新加载资源包的方法。
加载资源包后,只需通过 bundle.LoadAssetAsync(资源名,类型)便可加载所需的资源。

m_Dependencies

m_Dependencies记录了所有已加载资源的依赖包,以便在GetLoadedAssetBundle方法中判断资源包是否被完全加载(主体包和所有依赖包都被加载才算完成加载)。简化后的代码如下:

[C#] 纯文本查看 复制代码
IEnumerator OnLoadAssetBundle(包名)
{
      //获取依赖包
      string[] dependencies = m_AssetBundleManifest.GetAllDependencies(abName);
      m_Dependencies.Add(abName, dependencies); //更新依赖表
      //加载依赖包
      for (int i = 0; i < dependencies.Length; i++)
            OnLoadAssetBundle(XXX)  
  //然后加载主体资源
       download = WWW.LoadFromCacheOrDownload(包名)
       //更新加载表
       m_LoadedAssetBundles.Add(XXX)
}

AssetBundleInfo GetLoadedAssetBundle(包名)
 {
       //判断加载表
       AssetBundleInfo bundle = m_LoadedAssetBundles[包名];
       if (bundle == null) return null;
       //判断依赖包
       foreach (string 依赖包名 in m_Dependencies[包名])
       {
              if (m_LoadedAssetBundles[依赖包名]== null) 
                     return null;
       }
       return bundle;
}

m_LoadRequests

m_LoadRequests是一个<string, List<LoadAssetRequest>>类型的字典,LoadAssetRequest的定义如下,它用于异步加载后的回调。

Unity3D热更新LuaFramework入门实战24209.png

图:LoadAssetRequest

由于采用异步加载,加载资源的过程中,程序有可能发起同一个请求,多次加载似乎有些浪费,如下图所示。

Unity3D热更新LuaFramework入门实战24280.png

图:两次加载同一资源

更好的办法是,在收到第2次请求时先做判断,如果该资源正在加载,那先记录请求2的回调函数,待资源加载完成,调用所有请求该资源的回调函数,如下图所示。m_LoadRequests便记录每种资源的请求,使程序可以判断该资源是否正在加载,并从m_LoadRequests获取各个资源请求的回调函数。

Unity3D热更新LuaFramework入门实战24441.png

图:记录请求2的回调函数

简化后的代码如下:

[C#] 纯文本查看 复制代码
void LoadAsset(包名)
{
       If(m_LoadRequests[abName] == null)
       {
              m_LoadRequests[包名].Add(回调函数等);
              OnLoadAsset();
       }
       else
       {
              m_LoadRequests[包名].Add(回调函数等);
       }
}

IEnumerator OnLoadAsset(XXX)
{
       加载包
       加载资源
       foreach( request in  m_LoadRequests[包名] )
       {
              Request.回调函数();
       }
}



5、资源热更新

“资源热更新”和上一篇的“代码热更新”完全相同,开启更新模式后,将新的资源文件复制到服务器上,框架即可自动下载更新的资源。这里不再复述。

笔者也是刚刚接触LuaFramework不久,想看看是否适合于工作室接下来的项目,文章错误之处在所难免,请大家多加包涵。继续是广告时间:

《十六年的长度,记录中国独立游戏》笔者的一篇文章,盘点了1998年以来我国一些独立游戏,以及独立游戏作者的经历。相信对有志于开发独立游戏的读者有所帮助。
http://games.sina.com.cn/zl/duanpian/2015-04-03/1538151.shtml





回复

使用道具 举报

7日久生情
2711/5000
排名
83
昨日变化

5

主题

262

帖子

2711

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
2352
好友
6
蛮牛币
4940
威望
0
注册时间
2013-8-21
在线时间
701 小时
最后登录
2017-1-11

社区QQ达人

发表于 2016-7-17 09:06:27 | 显示全部楼层
好像不是针对unity最新版本的。

回复 支持 反对

使用道具 举报

5熟悉之中
932/1000
排名
2102
昨日变化
5

7

主题

242

帖子

932

积分

Rank: 5Rank: 5

UID
104110
好友
0
蛮牛币
674
威望
0
注册时间
2015-5-29
在线时间
235 小时
最后登录
2017-1-20
发表于 2016-7-17 10:43:29 | 显示全部楼层
本帖最后由 eagle1098 于 2016-7-17 18:51 编辑

相比于国外的独立游戏,国内独立游戏的创作更困难,但现在独立游戏更多的应该是移动端游戏,而且制作成功和盈利的也比较多吧。

回复 支持 反对

使用道具 举报

4四处流浪
382/500
排名
9166
昨日变化
7

2

主题

111

帖子

382

积分

Rank: 4

UID
16650
好友
0
蛮牛币
1180
威望
0
注册时间
2014-3-6
在线时间
176 小时
最后登录
2016-11-18
发表于 2016-7-19 10:01:01 | 显示全部楼层
来看看..希望有帮助

回复 支持 反对

使用道具 举报

5熟悉之中
709/1000
排名
3134
昨日变化
2

3

主题

224

帖子

709

积分

Rank: 5Rank: 5

UID
68430
好友
0
蛮牛币
3412
威望
0
注册时间
2015-1-14
在线时间
186 小时
最后登录
2017-1-18
发表于 2016-7-19 16:42:39 | 显示全部楼层
学习下~~
[发帖际遇]: 绝世love情缘 在论坛发帖时没有注意,被小偷偷去了 2 蛮牛币. 幸运榜 / 衰神榜

回复

使用道具 举报

3偶尔光临
297/300
排名
5686
昨日变化
45

6

主题

63

帖子

297

积分

Rank: 3Rank: 3Rank: 3

UID
148479
好友
1
蛮牛币
456
威望
0
注册时间
2016-5-13
在线时间
82 小时
最后登录
2017-1-19
发表于 2016-7-20 14:32:13 | 显示全部楼层
希望能有视频版的热更新入门实战1

回复 支持 反对

使用道具 举报

排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

 楼主| 发表于 2016-7-20 23:56:44 | 显示全部楼层
冰糖葫芦 发表于 2016-7-17 09:06
好像不是针对unity最新版本的。

Lz用的是5.2,但对更新版本应该也是适用的

回复 支持 反对

使用道具 举报

排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

 楼主| 发表于 2016-7-20 23:57:26 | 显示全部楼层
eagle1098 发表于 2016-7-17 10:43
相比于国外的独立游戏,国内独立游戏的创作更困难,但现在独立游戏更多的应该是移动端游戏,而且制作成功和 ...

是啊,不过当年做独立游戏和现在有很大不同,如今独立游戏这个词已经被用烂了

回复 支持 反对

使用道具 举报

排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

 楼主| 发表于 2016-7-20 23:57:29 | 显示全部楼层
eagle1098 发表于 2016-7-17 10:43
相比于国外的独立游戏,国内独立游戏的创作更困难,但现在独立游戏更多的应该是移动端游戏,而且制作成功和 ...

是啊,不过当年做独立游戏和现在有很大不同,如今独立游戏这个词已经被用烂了

回复 支持 反对

使用道具 举报

排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

 楼主| 发表于 2016-7-20 23:57:55 | 显示全部楼层
taohuacan 发表于 2016-7-19 10:01
来看看..希望有帮助

愿对大家有所帮助

回复 支持 反对

使用道具 举报

排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

 楼主| 发表于 2016-7-20 23:58:32 | 显示全部楼层
ZoneWu 发表于 2016-7-20 14:32
希望能有视频版的热更新入门实战1

这一系列一共会有10篇左右,要持续关注哦。

回复 支持 反对

使用道具 举报

排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

 楼主| 发表于 2016-7-20 23:58:42 | 显示全部楼层
ZoneWu 发表于 2016-7-20 14:32
希望能有视频版的热更新入门实战1

这一系列一共会有10篇左右,要持续关注哦。

回复 支持 反对

使用道具 举报

3偶尔光临
186/300
排名
7859
昨日变化
7

0

主题

16

帖子

186

积分

Rank: 3Rank: 3Rank: 3

UID
91025
好友
1
蛮牛币
247
威望
0
注册时间
2015-4-10
在线时间
83 小时
最后登录
2016-11-5
发表于 2016-8-24 10:49:52 | 显示全部楼层
顶楼主,感谢楼主分享。

回复 支持 反对

使用道具 举报

3偶尔光临
252/300
排名
9969
昨日变化
8

0

主题

75

帖子

252

积分

Rank: 3Rank: 3Rank: 3

UID
34026
好友
1
蛮牛币
77
威望
0
注册时间
2014-7-13
在线时间
123 小时
最后登录
2016-12-27
发表于 2016-10-15 11:49:03 | 显示全部楼层
请问是用到该资源的时候框架才会去服务器检查有无新版本资源,还是在框架启动的时候就去检查,或者能自定义更新的时间?

回复 支持 反对

使用道具 举报

排名
14579
昨日变化
9

12

主题

89

帖子

438

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
12
蛮牛币
1432
威望
0
注册时间
2014-11-6
在线时间
52 小时
最后登录
2017-1-20

专栏作家

 楼主| 发表于 2016-10-17 19:03:18 | 显示全部楼层
number13 发表于 2016-10-15 11:49
请问是用到该资源的时候框架才会去服务器检查有无新版本资源,还是在框架启动的时候就去检查,或者能自定义 ...

这里是启动时就去更新

回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表