关于大厅+子游戏的实现方案,很早就想做了,也参考了论坛中的实现方案,看了很多的帖子,也查了很多的资料,发现所有的实现方案都一样,简单说下我对于他们的实现方案的理解。
APP启动的时候会在main.js里初始化好所有的资源列表,加载资源的时候只能加载列表中存在的资源,现有方案的实现都是通过修改main实现,并且每一个子游戏 和 大厅都是一个独立项目,也就是每个游戏都是独立的运行环境,相互之前也无法共享资源,简单说下我认为这种方案的弊端:
-
**运行环境独立,资源无法共享。**导致公共资源只能放在大厅中预加载才能在子游戏中使用(因为资源加载过后会有缓存,所以可以在子游戏中使用)。 再举个列子,如果你有5款麻将,普通话的语音文件肯定是都一样的吧,难道发包要把这份资源拷贝5份?每次更新1款麻将都要更新1遍这个语音资源?这么做我觉得无法忍受。
-
**公共代码无法共用。**最基本的,网络层的代码需要在每个项目中拷贝一份,再加上其他自己框架性的代码,如果你的子游戏有十几二十个,想想你的公共代码要怎么处理。
-
**开发维护困难。**不知道使用这种方案的是将所有资源放到1个项目里开发,还是每个项目独立开发,如果是前者,开发完还需要将子游戏拷贝到相应项目构建资源,如果是后者也挺麻烦的。
-
之前看资料,好像还要解决uuid冲突问题,具体没尝试,不太清楚
以上是个人对现有大厅子游戏实现方案的理解,看到这里,我果断地放弃的这种做法
最近花了点时间,仔细推敲了下,自己实现了另一种方案
先说下自己对分包方案的理解和要求:
-
所谓大厅+子游戏 其实应该是一种资源管理,想要实现对特定资源的更新管理。
-
分包要实现 所有资源可以共用,所有代码可以共用。
-
开发维护要简单便捷,将大厅+所有子游戏 作为一个项目进行开发。
基于以上的要求,我们可以这么做:
-
将所谓大厅子游戏看作是1个完整项目。这样就可以使用公共资源和代码了
-
自己记录资源所属的 子游戏模块(比如上述5个麻将语音资源的实现,我们也可以将1份资源记录为属于N个子游戏模块)
-
每次构建所有的完整资源,构建完成后,根据自己的记录 将构建后的资源 按子游戏模块筛选出来
-
根据筛选的模块资源 生成每个模块的资源更新列表,即 project.manifest 和 version.manifest文件。
-
自己实现更新逻辑,更新某个特定模块资源。
以上就是大致的实现思路,下面说下我自己的做法 (此方案依赖编辑器提供的打包函数,仅适用于creator2.0以上)
-
写一份配置文件,以路径记录所属模块,可以将1份资源记录属于1个或多个模块
-
自己写一个扩展插件,利用编辑器构建API onBuildFinish函数, 在这个函数里 我们可以拿到所有的构建后的资源
这里可以获取所有构建资源的uuid,通过uuid得到资源路径,通过之前的配置文件,得到uuid所属的模块,然后自己记录下来。
可能用到的函数有
Editor.assetdb.uuidToUrl 通过uuid得到路径
buildResults.getDependencies(asset.uuid) 获取资源的依赖资源
Editor.assetdb.isMountByUuid 是否为系统内置资源 -
修改version_generator.js文件,根据之前得到的 uuid所属模块 的配置文件,分别生成每个模块的 project.manifest 和 version.manifest 文件。
其实这一步可以灵活的配置,比如我做了一个将大厅的资源包含在每个子游戏中,这样在更新子游戏时 就同时更新了大厅,省去了大厅的单独更新。 当然你也可以单独更新大厅,怎么做,你可以随意配置。 -
根据官方提供的热更新脚本,实现热更功能,这个脚本几乎不用做什么改动,只有1点需要注意:官方提供的热更机制,更新完成后,会生成名为 project.manifest 文件,我们需要将此文件改名为 对应模块的文件名, 子游戏_project.manifest。 因为热更新管理器的缓存机制,如果你不更改此文件,可能会导致其他子游戏无法更新。例如,更新完pdk,版本为1.0,更新完成后, 这时候再更新mj,版本同样为1.0,热更管理器会直接认为已经更新完了,因为本地存在的那份 project.manifest文件导致的。
这个方案的实现 不涉及到更改 main.js 文件。
有1点不好的地方是,更新完子游戏时,可能需要重启APP,当然,如果你确定你的子游戏中不包含公共部分的资源代码,也是可以不用重启的。
这些是我目前的想法,自己也是做了测试demo,成功的实现相关功能,但目前尚未用于生成环境(预计1个月内,我们自己的项目就要使用了),有兴趣的,可以参照这个思路,自己尝试实现看看。
0314补充:关于更新管理器的缓存机制,理解有些偏差,在下面12楼做出更正