這篇文章主要是我們團隊在使用Cocos Creator過程中的一些關于部署方面的實踐總結,標題黨了一回,嚴格來說,應該是《快看漫畫游戲研發(fā)團隊使用Cocos Creator構建部署最佳實踐》,對于其他團隊可能并不是。
之所以寫這篇文章,一是我剛開始接觸Cocos Creator的時候,發(fā)現構建部署方面的一些問題,針對性寫了3篇優(yōu)化的方案,隨著對Cocos Creator了解的深入,我發(fā)現了一些更好的替代方法,二是因為我們團隊隨著業(yè)務發(fā)展,又到了缺人的時候,出來刷刷臉,發(fā)點招聘廣告:Cocos Creator工程師快到碗里來。
不過你不用擔心,本文不會只是炒炒冷飯,這次涉及的內容覆蓋了構建部署的整個環(huán)節(jié),如果你剛好把代碼寫好了,你應該看看本文,它會告訴你怎么把你的代碼漂亮的部署到線上,并且這里涉及的代碼你都可以通過github查看。涉及知識點如下:
- 如何自定義loading頁面
- 圖片部署自動化壓縮優(yōu)化
- 減少loading頁面出現之前的白屏時間
- 代碼混淆與保護
- 文件資源增加md5版本號
- cdn緩存
由于我們游戲采用的是1.6版本,所以還保留了md5版本號的優(yōu)化,新的1.7版本已經比較完美支持md5的功能,但由于沒有在實踐中使用,所以還是基于1.6版本做一次總結,本質是一樣的。
本篇我們會基于Cocos Creator的官方示例做分析,我在原demo的基礎上增加了部署的腳本,部署到又拍云和騰訊云。為了展示自定義loading頁面的功能,我把這個游戲的loading頁面改了,如果有問題,麻煩官方聯系我下架。
1. 如何自定義loading頁面
這個需求官方其實是有提供解決方案的,官方文檔-“定制項目構建模板”的功能就可以實現這個需求,可能是文檔描述得不太清楚,我當時并沒有把這個功能跟“自定義加載首頁”聯系起來。
由于這個構建模板功能,我們就可以不用gulp插件輕松實現自定義首頁HTML,CSS,JS的功能了。怎么實現可以訪問本文的項目地址查看。
自定義loading頁面效果:
2. 圖片部署自動化壓縮優(yōu)化
通過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文件,能有效減少網絡不穩(wěn)定情況下進入游戲白屏的時間。
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后會對代碼進行壓縮優(yōu)化,但通過強大的chrome工具格式化代碼后,還是能輕松閱讀代碼的整體邏輯,在競爭激烈的游戲行業(yè),代碼保護力度是不足夠的。由于代碼暴露在前端,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['\x68\x6d\x41\x4c\x54']), '\x6c'),
cc['\x54']({
'S': cc['\x55'],
'O': {
'idx': 0x0,
'icon': cc[_0x490d30(_0xc91c('0x249'))],
'arrow': cc['\x4e\x6f\x64\x65'],
'anim': cc[a[_0xc91c('0x43d')]]
},
'_': function(b) {
this[a[_0xc91c('0x43e')](_0x490d30, _0xc91c('0x31c'))] = b[a[_0xc91c('0x43e')](_0x490d30, '\x30\x78\x36\x38')],
this[a[_0xc91c('0x43f')]] = b[_0x490d30(a[_0xc91c('0x440')])],
this[_0x490d30(a[_0xc91c('0x441')])][_0x490d30(a['\x6b\x77\x71\x63\x72'])] = b[_0x490d30(a[_0xc91c('0x442')])],
this[_0x490d30(_0xc91c('0x1c0'))]['\x6f\x6e'](a[_0xc91c('0x43e')](_0x490d30, a[_0xc91c('0x443')]), this[a['\x45\x79\x7a\x47\x44'](_0x490d30, a['\x6a\x64\x44\x61\x6e'])][_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調試工具就會觸發(fā)無限循環(huán)的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分發(fā)的功能,通過簡單配置,我相信你能折騰出來的,所以不再贅述。
這里主要做不同方案的演示,我部署了兩個方案:直接回源和cdn分發(fā)。
首次訪問
在Wifi網絡下,回源方案耗時6-10s,cdn分發(fā)方案耗時3-6s。
第二次訪問
由于增加了強緩存,無論是cdn還是回源,第二次訪問時間都在1-2s之間。
這個項目本身存在先天不足,例如圖片沒有合并,導致首次請求有116個,加載速度肯定會受影響。但通過cdn緩存方案,也能基本保證快速加載。
又拍cdn方案:
騰訊回源方案:
代碼我已經部署到了又拍云和騰訊云,大家可以點擊訪問感受加載速度。
cdn是比較好的優(yōu)化首次訪問網絡速度的方案,但cdn也不是必然比源站快,大家測試時發(fā)現回源更快也不必驚訝,本質上cdn節(jié)點就是距離你更近的代理服務器,但也有很多情況導致cdn緩慢,所以部署后還要通過工具多測試各個cdn節(jié)點的狀況。
最后
游戲優(yōu)化肯定不僅僅這幾條,有很多優(yōu)化要根據實際情況實際分析。但這6點實踐,應該可以解決論壇經常提到的緩存刷新,加載速度等部署相關的問題。
資源md5+cdn+強緩存 能解決80%H5游戲加載速度的問題,特別是第二次訪問,2秒打開輕輕松松,基本已經成為web前端優(yōu)化的工業(yè)標準方案。但現在很多線上的H5游戲還有很多走url參數+時間戳/md5的老方案,這種方案有很多弊端。希望通過本文,大家都能在自己的游戲內把資源md5+cdn+強緩存的方案貫徹執(zhí)行起來。其實很簡單,特別是Cocos Creator1.7版本后就更方便了。H5游戲的優(yōu)勢就是即點即玩,如果這點都做不到,就沒什么優(yōu)勢了。
說了這么多,你可能覺得實踐起來很麻煩,業(yè)務太多沒時間搞這些。
沒關系,本文買一送一,既然你看到這里,說明你也是有緣之人,我把代碼倉庫也贈送給你,例子源碼我放在了github cocos-fly上,有需要大家可以上去下載。
把gulpfile.js和releash.sh扒下來,只需要執(zhí)行命令:sh releash
,就可以一鍵構建出可發(fā)布的代碼。
線上示例+源碼+教程一條龍,還不趕緊引入自己的項目?。