资讯专栏INFORMATION COLUMN

Cocos Creator—最佳构建部署实践

caohaoyu / 1093人阅读

摘要:本篇我们会基于的官方示例做分析,我在原的基础上增加了部署的脚本,部署到又拍云和腾讯云。文件资源增加版本号版本号的方案跟之前的文章基本一致,这个流程在版本应该可以忽略了。

这篇文章主要是我们团队在使用Cocos Creator过程中的一些关于部署方面的实践总结,标题党了一回,严格来说,应该是《快看漫画游戏研发团队使用Cocos Creator构建部署最佳实践》,对于其他团队可能并不是。

之所以写这篇文章,一是我刚开始接触Cocos Creator的时候,发现构建部署方面的一些问题,针对性写了3篇优化的方案,随着对Cocos Creator了解的深入,我发现了一些更好的替代方法,二是因为我们团队随着业务发展,又到了缺人的时候,出来刷刷脸,发点招聘广告:Cocos Creator工程师快到碗里来。

不过你不用担心,本文不会只是炒炒冷饭,这次涉及的内容覆盖了构建部署的整个环节,如果你刚好把代码写好了,你应该看看本文,它会告诉你怎么把你的代码漂亮的部署到线上,并且这里涉及的代码你都可以通过github查看。涉及知识点如下:

如何自定义loading页面

图片部署自动化压缩优化

减少loading页面出现之前的白屏时间

代码混淆与保护

文件资源增加md5版本号

cdn缓存

由于我们游戏采用的是1.6版本,所以还保留了md5版本号的优化,新的1.7版本已经比较完美支持md5的功能,但由于没有在实践中使用,所以还是基于1.6版本做一次总结,本质是一样的。

本篇我们会基于Cocos Creator的官方示例做分析,我在原demo的基础上增加了部署的脚本,部署到又拍云和腾讯云。为了展示自定义loading页面的功能,我把这个游戏的loading页面改了,如果有问题,麻烦官方联系我下架。

1. 如何自定义loading页面

这个需求官方其实是有提供解决方案的,官方文档-“定制项目构建模板”的功能就可以实现这个需求,可能是文档描述得不太清楚,我当时并没有把这个功能跟“自定义加载首页”联系起来。

由于这个构建模板功能,我们就可以不用gulp插件轻松实现自定义首页HTML,CSS,JS的功能了。怎么实现可以访问本文的项目地址查看。

自定义loading页面效果:

2. 图片部署自动化压缩优化

通过gulp工具,在部署之前自动化处理一遍图片压缩流程,在无损压缩的情况下,既能保证图片的输出质量还能减少体积。有团队会手动采用tinypng或者其他压缩工具提前压缩,这样做也是可以的,但流程不好把控,原则上能自动化处理的尽量让机器来做,人是会累的但机器不会,也不会出错。

var imagemin = require("gulp-imagemin");
gulp.task("imagemin", function (cb) {
    gulp.src(["./build/web-mobile/**/*.png"])
        .pipe(imagemin([
            imagemin.gifsicle({interlaced: true}),
            imagemin.jpegtran({progressive: true}),
            imagemin.optipng({optimizationLevel: 5})
        ]))
        .pipe(gulp.dest("./build/web-mobile/"))
        .on("end", cb);
});`
3. 减少loading页面出现之前的白屏时间

通过gulp-htmlmin插件,把首屏的js,css文件合并到首页html文件,能有效减少网络不稳定情况下进入游戏白屏的时间。

var htmlmin = require("gulp-htmlmin");
gulp.task("htmlmin", ["imagemin"], function (cb) {
    gulp.src("./build/web-mobile/*.html")
        .pipe(fileInline())
        .pipe(htmlmin({
            collapseWhitespace: true,
            removeComments: true,
            minifyCSS: true
        }))
        .pipe(gulp.dest("./build/web-mobile/")
            .on("end", cb));
});

通过合并操作,首屏loading页面只需要加载index.html文件,在304情况下白屏时间只有142ms!

4. 代码混淆,代码保护

Cocos Creator引擎build后会对代码进行压缩优化,但通过强大的chrome工具格式化代码后,还是能轻松阅读代码的整体逻辑,在竞争激烈的游戏行业,代码保护力度是不足够的。由于代码暴露在前端,H5游戏不存在加密可言,但我们可以做一些工作,增加游戏被破解盗窃的难度。

gulp-javascript-obfuscator插件可以对代码进行可读性混淆,禁止开启chrome调试,域名绑定等功能,能很大程度保护自己的代码,这个插件还有其他很强大的功能,有兴趣可以访问github了解。但我不建议开启太多功能,毕竟对性能还是有一定影响。

var javascriptObfuscator = require("gulp-javascript-obfuscator");
gulp.task("obfuscator", ["htmlmin"], function (cb) {
    gulp.src(["./build/web-mobile/project.js"])
        .pipe(javascriptObfuscator({
            compact: true,
            domainLock: [".zz-game.com"],
            mangle: true,
            rotateStringArray: true,
            selfDefending: true,
            stringArray: true,
            target: "browser"
        }))
        .pipe(gulp.dest("./build/web-mobile")
            .on("end", cb));
});

我采用了最轻量的混淆方案,混淆前后对比:

混淆前:

TabCtrl: [function(t, e, i) {
        "use strict";
        cc._RF.push(e, "62208XJq9ZC2oNDeQGcbCab", "TabCtrl"),
        cc.Class({
            extends: cc.Component,
            properties: {
                idx: 0,
                icon: cc.Sprite,
                arrow: cc.Node,
                anim: cc.Animation
            },
            init: function(t) {
                this.sidebar = t.sidebar,
                this.idx = t.idx,
                this.icon.spriteFrame = t.iconSF,
                this.node.on("touchstart", this.onPressed.bind(this), this.node),
                this.arrow.scale = cc.p(0, 0)
            }
        }),
        cc._RF.pop()
    }
    , {}]
}, {}, ["ItemList", "ItemTemplate", "BackPackUI", "ButtonScaler", "ChargeUI", "EnergyCounter", "HeroSlot", "HomeUI", "PanelTransition", "ShopUI", "SubBtnsUI", "MainMenu", "MenuSidebar", "TabCtrl"]);

混淆后:

"l": [function(b, a, c) {
        "use strict";
        cc[_0xc008("0x12")][_0xc008("0x13")](a, _0xc008("0x98"), "l"),
        cc["T"]({
            "S": cc["U"],
            "O": {
                "idx": 0x0,
                "icon": cc[_0xc008("0x3e")],
                "arrow": cc["Node"],
                "anim": cc["Animation"]
            },
            "_": function(a) {
                this[_0xc008("0x68")] = a[_0xc008("0x68")],
                this["idx"] = a[_0xc008("0x7b")],
                this[_0xc008("0x66")][_0xc008("0x47")] = a[_0xc008("0x65")],
                this[_0xc008("0x1b")]["on"](_0xc008("0x99"), this[_0xc008("0x9a")][_0xc008("0x5e")](this), this[_0xc008("0x1b")]),
                this[_0xc008("0x9b")][_0xc008("0x9c")] = cc["p"](0x0, 0x0);
            }
        }),
        cc[_0xc008("0x12")][_0xc008("0x20")]();
    }
    , {}]
}, {}, ["i", "d", "f", "c", "j", "b", "h", "n", "a", "m", "g", "k", "e", "l"]);

在不影响性能的前提下,稍微做一些代码保护,还是不错的。如果你想让代码更恶心一点也是可以的:

a.DFsJp;
        cc[a[_0xc91c("0x43a")](_0x490d30, a[_0xc91c("0x43b")])][a[_0xc91c("0x43c")](_0x490d30, _0xc91c("0xe5"))](b, a[_0xc91c("0x43c")](_0x490d30, a["x68x6dx41x4cx54"]), "x6c"),
        cc["x54"]({
            "S": cc["x55"],
            "O": {
                "idx": 0x0,
                "icon": cc[_0x490d30(_0xc91c("0x249"))],
                "arrow": cc["x4ex6fx64x65"],
                "anim": cc[a[_0xc91c("0x43d")]]
            },
            "_": function(b) {
                this[a[_0xc91c("0x43e")](_0x490d30, _0xc91c("0x31c"))] = b[a[_0xc91c("0x43e")](_0x490d30, "x30x78x36x38")],
                this[a[_0xc91c("0x43f")]] = b[_0x490d30(a[_0xc91c("0x440")])],
                this[_0x490d30(a[_0xc91c("0x441")])][_0x490d30(a["x6bx77x71x63x72"])] = b[_0x490d30(a[_0xc91c("0x442")])],
                this[_0x490d30(_0xc91c("0x1c0"))]["x6fx6e"](a[_0xc91c("0x43e")](_0x490d30, a[_0xc91c("0x443")]), this[a["x45x79x7ax47x44"](_0x490d30, a["x6ax64x44x61x6e"])][_0x490d30(_0xc91c("0x2e0"))](this), this[a[_0xc91c("0x444")](_0x490d30, _0xc91c("0x1c0"))]),
                this[a[_0xc91c("0x445")](_0x490d30, _0xc91c("0x446"))][a[_0xc91c("0x445")](_0x490d30, a[_0xc91c("0x447")])] = cc["x70"](0x0, 0x0);

开启debugProtection功能:

打开chrome调试工具就会触发无限循环的dubugger,让chrome调试工具无法使用,增大破解难度。为了方便大家查看学习demo,线上版本我关闭了这个选项。

开启disableConsoleOutput功能:

禁止console.log功能,很多混淆代码,通过断点+console.log,可以方便把翻译后的代码输出,开启disableConsoleOutput,同样增加调试难度。为了把我们的广告无处不在,我同样把它关了。JavaScript obfuscator还有其他不错的功能,这里不再展开。

5. 文件资源增加md5版本号

版本号的方案跟之前的文章基本一致,这个流程在1.7版本应该可以忽略了。

gulp.task("resRev", ["obfuscator"], function (cb) {
    gulp.src(["./build/web-mobile/**/*.js", "./build/web-mobile/*.png"])
        .pipe(rev())
        .pipe(gulp.dest("./build/web-mobile/"))
        .pipe(rev.manifest())
        .pipe(gulp.dest("./build/web-mobile/")
            .on("end", cb));
});
gulp.task("default", ["resRev"], function (cb) {
    del(["./build/web-mobile/src"]);
    gulp.src(["./build/web-mobile/*.json", "./build/web-mobile/index.html"])
        .pipe(revCollector())
        .pipe(gulp.dest("./build/web-mobile/"));
    gulp.src(["./build/web-mobile/*.json", "./build/web-mobile/main*.js"])
        .pipe(revCollector({
            replaceReved: true
        }))
        .pipe(gulp.dest("./build/web-mobile/")
            .on("end", cb));
});

通过md5+强缓存,第二次加载基本是毫秒级,瞬开。

116个请求的页面,只需要109ms就能渲染出loading页面,完全加载所有资源只需要1.25s:

6. cdn缓存

最后是把代码部署到cdn,现在的云服务都提供cdn分发的功能,通过简单配置,我相信你能折腾出来的,所以不再赘述。

这里主要做不同方案的演示,我部署了两个方案:直接回源和cdn分发。

首次访问

在Wifi网络下,回源方案耗时6-10s,cdn分发方案耗时3-6s。

第二次访问

由于增加了强缓存,无论是cdn还是回源,第二次访问时间都在1-2s之间。

这个项目本身存在先天不足,例如图片没有合并,导致首次请求有116个,加载速度肯定会受影响。但通过cdn缓存方案,也能基本保证快速加载。

又拍cdn方案:

腾讯回源方案:

代码我已经部署到了又拍云和腾讯云,大家可以点击访问感受加载速度。

直接回源的部署方案,点击访问

采用cdn等优化方案,点击访问

cdn是比较好的优化首次访问网络速度的方案,但cdn也不是必然比源站快,大家测试时发现回源更快也不必惊讶,本质上cdn节点就是距离你更近的代理服务器,但也有很多情况导致cdn缓慢,所以部署后还要通过工具多测试各个cdn节点的状况。

最后

游戏优化肯定不仅仅这几条,有很多优化要根据实际情况实际分析。但这6点实践,应该可以解决论坛经常提到的缓存刷新,加载速度等部署相关的问题。

资源md5+cdn+强缓存 能解决80%H5游戏加载速度的问题,特别是第二次访问,2秒打开轻轻松松,基本已经成为web前端优化的工业标准方案。但现在很多线上的H5游戏还有很多走url参数+时间戳/md5的老方案,这种方案有很多弊端。希望通过本文,大家都能在自己的游戏内把资源md5+cdn+强缓存的方案贯彻执行起来。其实很简单,特别是Cocos Creator1.7版本后就更方便了。H5游戏的优势就是即点即玩,如果这点都做不到,就没什么优势了。

说了这么多,你可能觉得实践起来很麻烦,业务太多没时间搞这些。

没关系,本文买一送一,既然你看到这里,说明你也是有缘之人,我把代码仓库也赠送给你,例子源码我放在了github cocos-fly上,有需要大家可以上去下载。

把gulpfile.js和releash.sh扒下来,只需要执行命令:sh releash,就可以一键构建出可发布的代码。

线上示例+源码+教程一条龙,还不赶紧引入自己的项目?。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92394.html

相关文章

  • Cocos Creator—如何给资源打MD5版本号

    摘要:从年底开发组就说要支持,等了大半年,新的内测版本终于增加了的功能,但效果也是差强人意。实际上我不会把这几个和打版本号的。最后产出会把这几个文件合并到中。 Cocos Creator 是Cocos最新一代的游戏开发者工具,基于 Cocos2d-x,组件化,脚本化,数据驱动,跨平台发布。Cocos Creator的开发思路已经逐步跟Unity 3D靠拢,写起来也更方便快捷,开发效率更高。 ...

    lk20150415 评论0 收藏0
  • 小游戏开发上手体验 - Cocos Creator

    摘要:但开发的游戏是无法通过网页发给别人在线玩的,更不能做成微信小游戏。它使用作为开发语言,开发出的游戏可以直接生成微信小游戏网页安卓等平台上的版本。 微信群里最大的骚扰源有两种: 一是转发#吱口令#~!@#¥%……&*,长按复制此消息领红包之类的 另一种就是各种小程序和小游戏的分享 前天有同学无意间把一个小游戏分享到了答疑群中,我看了一下,其实游戏的代码逻辑并不复杂(简化版的跳一跳,套上个...

    zhiwei 评论0 收藏0
  • cocos creator 简单实战

    摘要:锚点位置确定后,所有子节点就会以父节点锚点所在位置作为坐标系原点。观察实际效果以下为实际效果,左侧打开栏目为不同手机分辨率模式。巨坑因为分辨率发生变化,导致节点大小位置都会发生变化。 项目地址:https://github.com/Iroha1024/... 一个小游戏的demo,以下简单地介绍了我关于cocos creator的一点理解和开发流程 版本:cocos creator v...

    taowen 评论0 收藏0
  • cocos creator 事件

    摘要:事件在做一个消除类游戏时,需要对点击的方块做出响应。普通节点注册事件在中如果需要相应事件,需要为该节点添加一个组件。,事件冒泡利用自定义事件的属性,实现冒泡。 cocos creator 事件 在做一个消除类游戏时,需要对点击的方块做出响应。代码很简单,可背后的原理还多着呢。 1. 普通节点注册click事件 在cc中如果需要相应click事件,需要为该节点添加一个Button组件。或...

    since1986 评论0 收藏0
  • 实践解析:Electron实现跨平台视频会议的几种思路

    摘要:而现在我们可以利用多种工具框架进行跨平台开发。实现视频会议的几种思路如何利用实现一个视频会议应用这主要取决于使用什么技术来实现作为业务核心的部分。通过与技术结合,实现了网页端多方音视频通讯,可以快速实现部分的开发。 作者简介:张乾泽,声网 Agora Web 研发工程师 对于在线教育、医疗、视频会议等场景来讲,开发面向 Windows、Mac 的跨平台客户端是必不可少的一步。在过去,每...

    xi4oh4o 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<