HTML5游戲引擎深度測(cè)評(píng)
最近看到網(wǎng)上一篇文章,標(biāo)題叫做《2016年 最火的 15 款 HTML5 游戲引擎》。目前針對(duì)HTML5游戲的解決方案已經(jīng)非常多,但誰(shuí)好誰(shuí)差卻沒(méi)有對(duì)比性資料。特意花了幾天時(shí)間,針對(duì)文章中出現(xiàn)的12款免費(fèi)開(kāi)源引擎做了一次相對(duì)完整的對(duì)比分析,希望能對(duì)大家有所幫助。
針對(duì)技術(shù)類產(chǎn)品對(duì)比,通常有多個(gè)維度進(jìn)行對(duì)比,不僅僅是技術(shù)層面,還有許多非技術(shù)層面的內(nèi)容會(huì)影響我們的使用結(jié)果。本文從如下幾個(gè)維度進(jìn)行多重對(duì)比。
- 2D與3D
- 編程語(yǔ)言
- 設(shè)計(jì)理念&功能
- 工作流
- 性能
- 學(xué)習(xí)資料
- 商業(yè)應(yīng)用
2D與3D、編程語(yǔ)言對(duì)比
2D與3D
游戲領(lǐng)域中,最直白的一種分類方法便是2D與3D的區(qū)分。通常我們都會(huì)認(rèn)為它們是游戲引擎領(lǐng)域兩類不同的產(chǎn)品。原文中提及的引擎確實(shí)是當(dāng)下最為流行的HTML5游戲引擎。很多引擎屬于2D、3D通吃類型,我們通過(guò)一個(gè)表格進(jìn)行對(duì)比。
編程語(yǔ)言
基于HTML5技術(shù)的游戲引擎,所需要的腳本必定是JavaScript,只有JavaScript腳本語(yǔ)言才能運(yùn)行于瀏覽器中。但目前市場(chǎng)上,出現(xiàn)了很多JavaScript代替品,例如TypeScript、CoffeeScript、LiveScript等等。不同語(yǔ)言直接的定位不同,語(yǔ)言哲學(xué)也不盡相同。一些游戲引擎在語(yǔ)言選擇上也頗有意思。
Engine | 2D Render | 3D Render | JavaScript | TypeScript |
---|---|---|---|---|
Three.js | NO | YES | YES | NO |
Phaser | YES | NO | YES | YES |
Pixi.js | YES | NO | YES | YES |
Egret | YES | YES | YES | YES |
enchant.js | YES | NO | YES | NO |
craftyJS | YES | NO | YES | NO |
Turbulenz | YES | YES | YES | YES |
cocos2d-js | YES | NO | YES | NO |
PlayCanvas | NO | YES | YES | NO |
melonJS | YES | NO | YES | NO |
Quintus | YES | NO | YES | NO |
Hilo | YES | NO | YES | NO |
結(jié)論
可以從表格中看出,下面三個(gè)引擎屬于2D和3D通吃類型。
- Egret
- Turbulenz
- PlayCanvas
在Web游戲領(lǐng)域勝出的編程語(yǔ)言是JavaScript和TypeScript。但絕大部分HTML5游戲引擎還是采用JavaScript語(yǔ)言。只有4款引擎選擇支持TypeScript。
從當(dāng)前前端技術(shù)圈環(huán)境分析,未來(lái)可能很多前端框架或者引擎會(huì)推出響應(yīng)的TypeScript語(yǔ)言分支,從AngularJS宣布將使用TypeScript開(kāi)發(fā)開(kāi)始,TypeScript在很大程度上被前端認(rèn)可。不得不說(shuō)微軟在開(kāi)源圈這一仗打得漂亮。
設(shè)計(jì)理念&功能
架構(gòu)設(shè)計(jì)是一門(mén)大學(xué)問(wèn),對(duì)于開(kāi)源引擎架構(gòu)的設(shè)計(jì)模式主要取決于作者的程序哲學(xué)觀點(diǎn)和產(chǎn)品定位。將設(shè)計(jì)思路和功能放在一起對(duì)比討論,比單獨(dú)功能討論更有參考意義。一個(gè)引擎的功能并非越多越好,功能應(yīng)圍繞引擎定位而定,這樣的思路在一些引擎中體現(xiàn)尤為明顯,下面我們針對(duì)每個(gè)引擎一一分析。
Three.js
定位
Three.js項(xiàng)目創(chuàng)建時(shí)間是在2010年的4月24日,到目前位置,應(yīng)該算是比較老牌的開(kāi)源項(xiàng)目了。事實(shí)上Three.js定義并非一個(gè)游戲引擎。在Github主頁(yè)中,作者很明確的定義了Three.js的定位,叫做“JavaScript 3D library”。它僅僅是一個(gè)基于JavaScript語(yǔ)言的3D庫(kù)而已。當(dāng)然,你可以用它來(lái)做任何事情,無(wú)論是游戲,還是炫酷的3D展示。
設(shè)計(jì)理念
Three.js在設(shè)計(jì)之處希望創(chuàng)建一個(gè)非常輕量級(jí)的3D庫(kù),能夠幫助開(kāi)發(fā)者快速搭建基于HTML5的3D內(nèi)容。同時(shí),通過(guò)暴露簡(jiǎn)單的API,將3D內(nèi)容的開(kāi)發(fā)復(fù)雜性降至最低。
渲染環(huán)境上,Three.js支持WebGL和CCS3D兩種渲染模式。從當(dāng)前使用量和標(biāo)準(zhǔn)普及程度來(lái)做分析看,開(kāi)發(fā)者更加傾向于WebGL渲染方式。
功能
文本主要想對(duì)2D游戲引擎做深入分析,所有沒(méi)有對(duì)Three.js的功能與那些流行的3D引擎加以對(duì)比。
Pixi.js
定位
很多人第一眼看到Pixi.js官網(wǎng),都會(huì)不自覺(jué)的認(rèn)為這是一款游戲引擎。但在主頁(yè)中作者對(duì)于Pixi.js的定義為“2D WebGL renderer with canvas fallback”,翻譯為中文是一款依賴于canvas的WebGL渲染器。所以當(dāng)你看到Pixi.js提供了為數(shù)不多的功能時(shí),請(qǐng)不要驚訝,因?yàn)樗皇且豢钿秩酒鳌?/p>
設(shè)計(jì)理念
Pixi.js的設(shè)計(jì)理念很多程度來(lái)源于它的定位,只做渲染器,要把渲染功能做到最強(qiáng)。而這樣的定位,則會(huì)讓Pixi.js成為其他引擎的渲染內(nèi)核。你經(jīng)常能看到一些游戲引擎,或者產(chǎn)品都基于Pixi.js而開(kāi)發(fā)。
最求極致的渲染性能是Pixi.js的首要任務(wù),為了讓Pixi.js更加易于使用,作者在API設(shè)計(jì)上更加參考非常成熟的2D渲染架構(gòu) —— Flash,并且提供的API也盡量參考了ActionScript。
例如創(chuàng)建一個(gè)顯示對(duì)象,在Pixi.js中被封裝為 PIXI.Sprite。如果需要顯示圖像,借助 PIXI.PIXI.Texture紋理進(jìn)行渲染數(shù)據(jù)填充。最終設(shè)置顯示對(duì)象的坐標(biāo),代碼看起來(lái)就像下面這樣。
var stage = new PIXI.Container(); var texture = PIXI.Texture.fromImage('bunny.jpg'); var bunny = new PIXI.Sprite(texture); bunny.position.x = 80; bunny.position.y = 60; stage.addChild(bunny);
Pixi.js中的顯示架構(gòu)完全參考Flash設(shè)計(jì),所有顯示對(duì)象組合為一個(gè)樹(shù)狀數(shù)據(jù)結(jié)構(gòu),但內(nèi)部已針對(duì)WebGL渲染方式進(jìn)行過(guò)優(yōu)化,上層使用起來(lái)和Flash并無(wú)太大差別。
功能
游戲引擎中的功能,我們可以細(xì)分非常多分類,一篇文章無(wú)法講解所有分類細(xì)節(jié)講解明白。我將所有功能做了一個(gè)二級(jí)分類,方便分析。

Phaser
定位
刻意將Pixi.js放在前面分析,因?yàn)镻haser本身并沒(méi)有自己的渲染核心。就像Pixi.js的定位不一樣,Phaser的定位是 "Desktop and Mobile HTML5 game framework",中為稱之為“桌面與移動(dòng)端的HTML5游戲框架”。Phaser并不把自己定義為Engine,而是框架。所以,當(dāng)你看到Phaser的功能設(shè)計(jì)和它的渲染內(nèi)核時(shí)就不會(huì)經(jīng)驗(yàn)了。
設(shè)計(jì)理念
因?yàn)閷⒆约憾ㄎ粸橛螒蚩蚣?,所以Phaser在游戲功能方面顯得相當(dāng)全面,你能想得到的絕大部分功能Phaser已經(jīng)替你實(shí)現(xiàn)了。在渲染方面,Phaser并沒(méi)有自己的渲染內(nèi)核,而是直接引用了Pixi.js。這確實(shí)是個(gè)明智之舉,因?yàn)镻ixi.js在渲染性能方面非常強(qiáng)悍。前面已經(jīng)提及編程語(yǔ)言,游戲開(kāi)發(fā)本身邏輯復(fù)雜,算法較多,Phaser提供對(duì)TypeScript的支持也是非常明知的。
架構(gòu)方面,Phaser進(jìn)行非常多的高度封裝。就顯示部分而言,如果你使用過(guò)Pixi.js就是發(fā)現(xiàn),設(shè)計(jì)思路本身差別不大,但API使用起來(lái)則方便很多。Phaser為一準(zhǔn)備好了游戲所需要的一切。當(dāng)我們像創(chuàng)建一個(gè)游戲界面時(shí),可以在Phaser初始化時(shí)針對(duì)不同階段進(jìn)行定制。
- var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });
正向上面這行代碼,Phaser為我們定義了 preload 、 create 、 update 等方法,使用時(shí)只需要填寫(xiě)callback函數(shù)即可。在資源加載時(shí),Phaser會(huì)為你調(diào)用 preload 回調(diào)。 當(dāng)畫(huà)面刷新時(shí),可以調(diào)用 update 回調(diào)。
其他方面,信號(hào)和插件系統(tǒng)算是Phaser的最大特色了。
功能
Phaser功能眾多,但絕大部分應(yīng)用其他第三方作為實(shí)現(xiàn)。

Egret
定位
Egret算是HTML5游戲引擎中的新起之秀,其定位已不單純?yōu)镠TML5游戲引擎。官方將其定位為“游戲解決方案”,同時(shí)也并未過(guò)多提及HTML5。究其原因在于Egret不僅僅提供了一個(gè)基于HTML5技術(shù)的游戲引擎,更是提供了原生打包工具和眾多周邊產(chǎn)品,使其成為“解決方案”。
設(shè)計(jì)理念
這里單獨(dú)分析Egret Engine這個(gè)產(chǎn)品,其語(yǔ)言使用TypeScript,有2D和3D版本。在架構(gòu)設(shè)計(jì)上,同Pixi.js一樣,參考了Flash成熟的2D架構(gòu)體系。API方面,也參考了ActionScript。不僅如此,由于TypeScript的緣故,在事件系統(tǒng)中,也仿照ActionScript實(shí)現(xiàn)了 addEventListener 這樣的事件注冊(cè)機(jī)制。
內(nèi)核方面,Egret Engine采用了模塊化的設(shè)計(jì)。這樣可以將不同的功能進(jìn)行解耦。更加有趣的是,F(xiàn)lash中引以為傲的自動(dòng)臟矩形技術(shù)在Egret Engine中也被實(shí)現(xiàn)。在canvas模式下,臟矩形會(huì)是渲染性能得到提升,比其他引擎更加有優(yōu)勢(shì)。
如果你會(huì)Flash,那么Egret Engine對(duì)你來(lái)說(shuō)不需要過(guò)多的學(xué)習(xí)即可上手。
功能
Egret Engine由于模塊化設(shè)計(jì)的原因,將不同功能放到了不同模塊中。這些模塊以庫(kù)的形式提供,下面表中是所有支持模塊的總和,但不含平臺(tái)API部分,例如微信API的封裝。

enchant.js
定位
enchant.js并非一個(gè)引擎,而是一個(gè)框架。同時(shí),enchant.js也不僅僅用于游戲,還可以用于app。
設(shè)計(jì)理念
鑒于支持游戲開(kāi)發(fā)和APP開(kāi)發(fā),這個(gè)框架必定會(huì)顧全一些東西,不能在游戲方面放開(kāi)手腳。架構(gòu)設(shè)計(jì)上,沒(méi)講所有的元素全部按照OOP方式設(shè)計(jì),內(nèi)部使用實(shí)踐驅(qū)動(dòng),并有效的結(jié)合了異步處理。游戲方面則僅僅對(duì)動(dòng)畫(huà)相關(guān)功能做了支持。enchant.js框架提供了一套插件機(jī)制,你可以將使用到的功能模塊作為插件注入到enchant.js框架中。
enchant.js還特意提供了一個(gè)在線的圖像庫(kù),方便開(kāi)發(fā)者免費(fèi)使用其中的素材。當(dāng)從游戲效果來(lái)看,以小游戲居多。
功能
enchant.js框架自身提供的功能非常有限,如果需要其他功能,必須自己擴(kuò)展或者尋找響應(yīng)的插件。

craftyJS
定位
craftyJS將自己定義為針對(duì)JavaScript游戲的框架。
設(shè)計(jì)理念
由于框架的定位,craftyJS在設(shè)計(jì)上提供了一些系統(tǒng)級(jí)別支持,例如將canvas和Dom兩種渲染方式封裝為同一套API,盡量小的文件體積,實(shí)體組件系統(tǒng),顯示對(duì)象封裝,碰撞檢測(cè),事件系統(tǒng),還有很多功能組件模塊。所有的模塊都依賴于實(shí)體組件系統(tǒng)的設(shè)計(jì)。
在實(shí)際測(cè)試中,craftyJS在API上的設(shè)計(jì)思路也是使用起來(lái)最為不舒服的一個(gè)。
功能

Turbulenz
定位
Turbulenz引擎實(shí)際上是為自己的游戲渠道中的游戲提供的游戲引擎。因?yàn)楹妥陨砬澜壎?,所以在引擎中提供了很多l(xiāng)ow level API。借助這些底層API,可以呼叫Turbulenz游戲渠道中的一些系統(tǒng)級(jí)別功能。
設(shè)計(jì)理念
由于Turbulenz引擎更多的為自己設(shè)計(jì),更多的提供runtime支持,從嚴(yán)格意義上將,Turbulenz引擎不算是純正的HTML5游戲引擎。為了滿足其自身渠道的需求,Turbulenz引擎力求增加更加完整的功能,同時(shí)提高其運(yùn)行性能。
功能
由于Turbulenz對(duì)很多功能做了擴(kuò)展,同時(shí)推出Low Level API和 High Level API。這里不再對(duì)其中龐雜的系統(tǒng)進(jìn)行功能分析,大家如果有興趣可以到其官網(wǎng)查看。
cocos2d-js
定位
cocos2d-js是喊著Cocos2D-X的金鑰匙出身的,它僅僅是Cocos2D-X的一個(gè)HTML5實(shí)現(xiàn)的分支。
設(shè)計(jì)理念
cocos2d-js和Cocos2D-X的設(shè)計(jì)理念相同,你能夠看到所有的API以及語(yǔ)法都完全參考Cocos2D-X。國(guó)內(nèi)對(duì)于Cocos2D-X已經(jīng)非常了解,這里就不做過(guò)多介紹。
功能
cocos2d-js的功能提供的相當(dāng)完整,你在游戲中需要的功能幾乎都能夠找到。

PlayCanvas
定位
PlayCanvas主要用于3D渲染,本文還是以2D討論為主,對(duì)PlayCanvas的分析就不做過(guò)多分析。
melonJS
定位
melonJS是一個(gè)輕量級(jí)的HTML5游戲框架,并且通過(guò)插件機(jī)制擴(kuò)展其功能。
設(shè)計(jì)理念
melonJS在所有的功能設(shè)計(jì)上都是輕量級(jí)的,你可以看到很多功能,并且在此基礎(chǔ)之上搭建你自己所需要的功能模塊。melonJS對(duì)于Tiled Map支持非常好,在兼容性方面也是melonJS關(guān)注的重點(diǎn)。
功能

Quintus
定位
Quintus將自己定位為簡(jiǎn)單好用的JavaScript游戲引擎,同時(shí)支持移動(dòng)和PC端。
設(shè)計(jì)理念
Quintus設(shè)計(jì)為模塊化和輕量化,盡量使用簡(jiǎn)潔友好的JavaScript語(yǔ)法。在JavaScript的API結(jié)構(gòu)設(shè)計(jì)中,盡量使用標(biāo)準(zhǔn)的OOP模式。Quintus還借助了jQuery,并通過(guò)jQuery插件實(shí)現(xiàn)事件和一個(gè)選擇器的語(yǔ)法。語(yǔ)言設(shè)計(jì)層面上Quintus沒(méi)有設(shè)計(jì)限制使用傳統(tǒng)的繼承,這使得其中得組件模型更加容易被復(fù)用。
功能
Quintus自身并不支持WebGL,同時(shí)提供的功能也較少,在Github中排名也很靠后。

Hilo
定位
Hilo這個(gè)引擎來(lái)源于阿里前端團(tuán)隊(duì),從官網(wǎng)的主頁(yè)上看,這個(gè)引擎的定位比較模糊。Hilo作為一個(gè)跨終端的互動(dòng)小游戲解決方案,同時(shí)有稱綜合解決方案。從它的演變來(lái)看,Hilo屬于阿里前端在實(shí)踐總總結(jié)出來(lái)的一套工具庫(kù)。整體引擎并非最初有計(jì)劃設(shè)計(jì)構(gòu)想。
設(shè)計(jì)理念
從Hilo支持的特性上看,Hilo的設(shè)計(jì)思路更加偏向與前端開(kāi)發(fā)者,而非游戲開(kāi)發(fā)者。Hilo提供了多種模塊范式的包裝版本,實(shí)際上在滿足不同前端開(kāi)發(fā)者習(xí)慣。這些特性完全是前端工程師所偏好的內(nèi)容,對(duì)于游戲來(lái)講,這些內(nèi)容可能優(yōu)先級(jí)并非最高,作為阿里內(nèi)部團(tuán)隊(duì)的常用引擎,對(duì)于阿里來(lái)說(shuō)應(yīng)該非常合適,應(yīng)用場(chǎng)景做簡(jiǎn)單營(yíng)銷互動(dòng)小游戲足以。
功能
Hilo功能相對(duì)比較簡(jiǎn)單,對(duì)于游戲開(kāi)發(fā)來(lái)說(shuō),缺失功能較多。

工作流
對(duì)團(tuán)隊(duì)開(kāi)發(fā)來(lái)講,工作流搭建是非常重要的,我個(gè)人比較看重這點(diǎn)。如果是小型團(tuán)隊(duì)或者個(gè)人開(kāi)發(fā)者可能對(duì)此需求并不大。當(dāng)項(xiàng)目規(guī)模變大時(shí),一個(gè)好的工作流會(huì)事半功倍。
因?yàn)橐娴墓δ懿煌?,所以涉及的工具也?huì)有所差異,這里就不再做表對(duì)比了。
Three.js
3D并不在本篇文章的討論范圍之內(nèi),同時(shí)Three.js也并非游戲引擎,不存在游戲開(kāi)發(fā)工作流一說(shuō)。這里簡(jiǎn)單介紹一下Three.js所提供的在線編輯器。
Three.js提供的在線編輯器應(yīng)該是基于Three.js開(kāi)發(fā)的,功能不多,但相當(dāng)小巧。

Pixi.js
Pixi.js作為一個(gè)渲染器,其工具支持也是相當(dāng)清爽,除了一個(gè)程序庫(kù)之外,沒(méi)有提供任何工具。
Phaser
Phaser和Pixi.js一樣,沒(méi)有提供任何工具支持,在其官網(wǎng)上只是推薦了兩個(gè)代碼編輯器。還提供了一個(gè)簡(jiǎn)單的在線代碼編輯器。

Egret
Egret提供的工具非常多,也復(fù)合其解決方案的定位。在Egret整個(gè)體系下你可以看到如下工具支撐。
Egret Wing:Egret出品的一個(gè)IDE編輯器。在提供代碼編輯功能的同時(shí),還內(nèi)置可視化的UI編輯器。與Egret Engine中的GUI、EUI框架配合使用。

ResDepot:這是個(gè)小工具,用來(lái)配置游戲資源加載表。如果游戲資源多的話,用這個(gè)小工具拖拽一下就完成了。
TextureMerger:一個(gè)紋理合并的小工具,功能有點(diǎn)像TexturePacker。
DragonBones Pro:針對(duì)Egret中骨骼動(dòng)畫(huà)解決方案提供的DragonBones動(dòng)畫(huà)編輯器。

Egret Inspector:一個(gè)基于Chrome瀏覽器的插件,可以針對(duì)Egret游戲進(jìn)行調(diào)試。
Egret iOS & Android Support:這兩個(gè)東西可以將你的HTML5游戲打包成原生APP。
還有一些其他的工具,但定位與游戲開(kāi)發(fā)不同,有興趣可以去它的官網(wǎng)看。
從上面的分析看出,Egret在工作流的支持上做的還是非常完成的,從Wing的代碼編寫(xiě),到ResDepot和TextureMerger的資源整合,再到Inspector調(diào)試,和原生打包。游戲開(kāi)發(fā)過(guò)程中的每個(gè)環(huán)節(jié)基本都有工具支撐。
enchant.js
enchant.js 沒(méi)有提供任何工具支撐,在官網(wǎng)中也沒(méi)有任何相關(guān)支持工具的介紹。
craftyJS
craftyJS也沒(méi)有提供任何工具支撐,僅僅是一個(gè)開(kāi)源代碼庫(kù)。
Turbulenz
Turbulenz在你下載的目錄中包含了很多工具,大部分與格式轉(zhuǎn)換相關(guān)。所有工具均為命令含小工具,沒(méi)有提供任何可視化操作軟件支持。
cocos2d-js
Cocos2d-js近年來(lái)變化很大,但對(duì)于JS這個(gè)分支的支持卻少之又少。前一段時(shí)間新出了一個(gè)工具叫做Cocos Creator。我沒(méi)有具體使用過(guò),但看截圖仿佛有Unity3D的影子。從介紹中看,應(yīng)該對(duì)游戲支持還是不錯(cuò)的,編輯方面目前還欠缺。

PlayCanvas
PlayCanvas也提供了一個(gè)在線編輯器,不過(guò)是針對(duì)它的3D功能。編輯器看上去和Three.js提供的在線編輯器份很相似。這里直接借用官方文檔中的截圖給大家看一下。

melonJS
melonJS除了源碼庫(kù)以外,也沒(méi)有提供任何工具支持。但在其官方主頁(yè)中,包含幾個(gè)其他編輯器的連接。比如著名的Tiled地圖編輯器等。
Quintus
Quintus沒(méi)有提供任何工具支撐。
Hilo
Hilo沒(méi)有提供任何工具支撐。
總結(jié)
結(jié)果并不出乎意料,對(duì)于開(kāi)源游戲引擎來(lái)講,維護(hù)庫(kù)就是耗費(fèi)作者很大一部分精力,更何況去制作編輯器之類的軟件產(chǎn)品。很多引擎都會(huì)依賴一些比較流行的第三方工具,例如Tiled、TexturePacker等等。雖然可以實(shí)現(xiàn)功能,但整個(gè)工作流搭配起來(lái)還是多多少少會(huì)有一些問(wèn)題。只有Egret和Cocos2D-js提供了相關(guān)可視化編輯工具。而這兩對(duì)于工作流的理解則完全不同。從產(chǎn)品中不難看出,Cocos2D-JS更像Unity3D,提供一個(gè)大而全的軟件給開(kāi)發(fā)者用。Egret則是什么角色用什么工具,將產(chǎn)品按照角色劃分,針對(duì)不同角色和開(kāi)發(fā)流程中的各個(gè)環(huán)節(jié)進(jìn)行產(chǎn)品設(shè)計(jì)。
相對(duì)來(lái)說(shuō),Egret的這種方式使得每個(gè)工具更加垂直,能夠做的功能也更加深入,不會(huì)讓工具顯得臃腫。而Cocos Creator則力求完整,一個(gè)軟件解決所有事情。
性能
性能測(cè)試上,我只針對(duì)2D游戲引擎做了一個(gè)渲染壓力測(cè)試。
測(cè)試內(nèi)容為同屏渲染對(duì)象數(shù)量相同的情況下進(jìn)行幀頻數(shù)據(jù)對(duì)比,為了保證測(cè)試的公平性,我使用同一臺(tái)電腦,相同版本的Chrome瀏覽器進(jìn)行測(cè)試,游戲場(chǎng)景尺寸均為800*600,顯示的圖片也為同一張。每個(gè)引擎進(jìn)行同屏5000、10000、20000個(gè)顯示對(duì)象渲染。
其中craftyjs引擎渲染出現(xiàn)問(wèn)題,這里不作數(shù)據(jù)對(duì)比。
Quintus引擎不支持WebGL渲染模式,因此這里頁(yè)不作數(shù)據(jù)對(duì)比。
Phaser渲染內(nèi)核使用Pixi.js,因此Phaser渲染數(shù)據(jù)參考Pixi.js結(jié)果。
所有引擎編寫(xiě)的代碼大致相同,開(kāi)始做for循環(huán),創(chuàng)建定量顯示對(duì)象,然后在循環(huán)中對(duì)每個(gè)顯示對(duì)象做旋轉(zhuǎn)操作。
測(cè)試代碼如下:
Pixi.js
- var renderer = PIXI.autoDetectRenderer(800, 600,{backgroundColor : 0x1099bb}); document.body.appendChild(renderer.view); var stage = new PIXI.Container(); var texture = PIXI.Texture.fromImage('bunny.jpg'); var tnum = 5000; console.log("render Object Number:",tnum); var bunnys = []; for(var i=0;i<tnum;i++) { var bunny = new PIXI.Sprite(texture); bunny.position.x = Math.random()*800; bunny.position.y = Math.random()*600; stage.addChild(bunny); bunnys.push(bunny); } animate(); function animate() { requestAnimationFrame(animate); for(var i=0;i<tnum;i++) { bunnys[i].rotation += 0.1; } renderer.render(stage); }
Egret
- class Main extends egret.DisplayObjectContainer { public constructor() { super(); this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this); } private tnum:number = 100000; private bunnys:egret.Bitmap[] = []; private onAddToStage(event:egret.Event) { console.log("render Object Number:",this.tnum); this.stage.dirtyRegionPolicy = egret.DirtyRegionPolicy.OFF; RES.getResByUrl('resource/bunny.jpg',this.onComplete,this,RES.ResourceItem.TYPE_IMAGE); } private onComplete(event:any) { var img:egret.Texture = <egret.Texture>event; for(var i:number=0;i<this.tnum;i++) { var bunny = new egret.Bitmap(img); bunny.x = Math.random()*800; bunny.y = Math.random()*600; this.addChild(bunny); this.bunnys.push(bunny); } this.addEventListener(egret.Event.ENTER_FRAME, this.animate,this); } private animate(evt:egret.Event) { for(var i:number=0;i<this.tnum;i++) { this.bunnys[i].rotation += 1; } } }
enchant.js
- enchant(); window.onload = function () { var game = new Game(800, 600); game.fps = 60; game.preload('bunny.jpg'); game.onload = function() { var tnum = 100000; console.log("render Object Number:",tnum); var bunnys = []; var scene = new Scene(); game.pushScene(scene); for(var i=0;i<tnum;i++) { var sprite = new Sprite(50, 50); sprite.image = game.assets['bunny.jpg']; sprite.x = Math.random()*800; sprite.y = Math.random()*600; scene.addChild(sprite); bunnys.push(sprite); } game.addEventListener('enterframe', function() { for(var i=0;i<tnum;i++) { bunnys[i].rotation += 1; } }); }; game.start(); };
Turbulenz
TurbulenzEngine = WebGLTurbulenzEngine.create({ canvas: document.getElementById("canvas") }); var graphicsDevice = TurbulenzEngine.createGraphicsDevice({}); var draw2D = Draw2D.create({ graphicsDevice: graphicsDevice }); var bgColor = [1.0, 1.0, 0.0, 1.0]; var tnum = 50000; console.log("render Object Number:", tnum); var bunnys = []; for (var i = 0; i < tnum; i++) { var sprite = Draw2DSprite.create({ width: 50, height: 50, x: Math.random() * 800, y: Math.random() * 600, color: [1.0, 1.0, 1.0, 1.0], rotation: Math.PI / 4 }); bunnys.push(sprite); } var texture = graphicsDevice.createTexture({ src: "bunny2.jpg", mipmaps: true, onload: function (texture) { if (texture) { for (var i = 0; i < tnum; i++) { var sprite = bunnys[i]; sprite.setTexture(texture); sprite.setTextureRectangle([0, 0, texture.width, texture.height]); } } } }); var PI2 = Math.PI * 2; var rotateAngle = PI2 / 360; // 1 deg per frame function update() { if (graphicsDevice.beginFrame()) { graphicsDevice.clear(bgColor, 1.0); draw2D.begin(); for (var i = 0; i < tnum; i++) { var sprite = bunnys[i]; sprite.rotation += rotateAngle; sprite.rotation %= PI2; // Wrap rotation at PI * 2 draw2D.drawSprite(sprite); } draw2D.end(); graphicsDevice.endFrame(); } } function render() { var tnum = 5000; console.log("render Object Number:", tnum); for (var i = 0; i < tnum; i++) { sprite.position.x = Math.random() * 800; sprite.position.y = Math.random() * 600; } }
cocos2d-js
- window.onload = function(){ cc.game.onStart = function(){ //load resources cc.LoaderScene.preload(["bunny.jpg"], function () { var tnum = 100000; console.log("render Object Number:",tnum); var bunnys = []; var MyScene = cc.Scene.extend({ onEnter:function () { this._super(); var batchNode = cc.SpriteBatchNode.create("bunny.jpg"); this.addChild(batchNode); for(var i=0;i<tnum;i++) { var sprite = cc.Sprite.create("bunny.jpg"); sprite.setPosition((Math.random()*800), (Math.random()*600)); batchNode.addChild(sprite); bunnys.push(sprite); } this.scheduleUpdate(); }, update:function () { for(var i=0;i<tnum;i++) { bunnys[i].setRotation(bunnys[i].getRotation()+1); } this.scheduleUpdate(); } }); cc.director.runScene(new MyScene()); }, this); }; cc.game.run("gameCanvas"); };
melonJS
- var PlayScreen = me.ScreenObject.extend( { onResetEvent: function() { me.game.world.addChild(new me.ColorLayer("background", "#5E3F66", 0), 0); for (var i = 0; i < 5000; i++) { me.game.world.addChild(new Smilie(i), 3); } } }); var Smilie = me.Sprite.extend({ init : function (i) { this._super( me.Sprite, "init", [ (-15).random(800), (-15).random(600), { image: me.loader.getImage(game.assets[0].name) ,width : 50 ,height : 50 } ] ); this.rotation = 0; this.alwaysUpdate = true; }, update : function () { this.rotation += 3/180*Math.PI; thisthis.angle = this.rotation ; return true; },} );
Hilo
- function init(){ var stage = new Hilo.Stage({ renderType:'canvas', container: gameContainer, width: 800, height: 600 }); var sum = 5000; var bitmaps = []; var ticker = new Hilo.Ticker(); ticker.addTick(stage); ticker.start(true); for(var i = 0; i < sum; i++) { var bmp = new Hilo.Bitmap({ image: 'images/hero.jpg', rect: [0, 0, 50, 50], x: Math.random()*800, y: Math.random()*600 }).addTo(stage); bitmaps.push(bmp); } function animate() { requestAnimationFrame(animate); for(var i = 0; i < sum; i++) { bitmaps[i].rotation += 0.1; } } animate(); }
我的電腦配置如下:

最終測(cè)試結(jié)果
Engine | 5000 Display | 10000 Display | 20000 Display |
---|---|---|---|
Pixi.js | 60fps | 60fps | 60fps |
Egret | 60fps | 45fps | 24fps |
enchant.js | 7fps | 4fps | 2fps |
Turbulenz | 60fps | 60fps | 60fps |
cocos2d-js | 60fps | 32fps | 15fps |
melonJS | 4fps | 崩潰 | 崩潰 |
Hilo | 12fps | 6fps | 3fps |
結(jié)論
按照上述測(cè)試方法,我們可以對(duì)引擎性能排名做一個(gè)大致排列:
第一名:Pixi.js 和 Turbulenz
第二名:Egret
第三名:Cocos2d-js
第四名:Hilo
第五名:enchant.js
第六名:melonJS
最后放出一張測(cè)試時(shí)效果圖

學(xué)習(xí)資料
通常情況下,我們都會(huì)選擇一個(gè)資料較全的產(chǎn)品進(jìn)行學(xué)習(xí)使用,畢竟使用過(guò)程中會(huì)遇到各種各樣的問(wèn)題?,F(xiàn)在游戲引擎的文檔,討論組等都已經(jīng)成為了產(chǎn)品標(biāo)配。下面這個(gè)表格就對(duì)各個(gè)引擎的這些“標(biāo)配”做一個(gè)對(duì)比。
Engine | Document | API Document | examples | forum | IRC&Other | Language |
---|---|---|---|---|---|---|
Three.js | YES | YES | YES | 第三方 | YES | EN |
Phaser | YES | YES | YES | 第三方 | YES | EN |
Pixi.js | YES | YES | YES | 第三方 | YES | EN |
Egret | YES | YES | YES | YES | YES | CN |
enchant.js | YES | YES | NO | NO | NO | JP EN |
craftyJS | YES | YES | NO | 第三方 | NO | EN |
Turbulenz | YES | YES | YES | 第三方 | 第三方 | EN |
cocos2d-js | YES | YES | YES | YES | YES | CN EN |
PlayCanvas | YES | YES | YES | YES | YES | EN |
melonJS | YES | YES | YES | NO | YES | EN |
Quintus | YES | YES | NO | YES | NO | EN |
Hilo | YES | YES | YES | NO | NO | CN |
結(jié)論
從上面對(duì)比表格可以看出,絕大部分引擎在文檔教程方面做的還是比較深入的,但完成程度不同。大部分都為英文文檔,對(duì)于國(guó)內(nèi)的開(kāi)發(fā)者來(lái)說(shuō)可能學(xué)習(xí)起來(lái)成本略高。其中兩個(gè)支持中文的引擎Egret、Hilo均為國(guó)人產(chǎn)品,這兩款引擎在文檔方面,Egret做的相當(dāng)優(yōu)秀,開(kāi)發(fā)者可以從它的edn.egret.com中查閱大量中文資料。
在學(xué)習(xí)難度上,Egret算是最為簡(jiǎn)單的,無(wú)論從完整度還是中文普及度上。
商業(yè)應(yīng)用
這部分對(duì)比是在商業(yè)產(chǎn)品應(yīng)用中的占比情況。一個(gè)引擎被商業(yè)產(chǎn)品應(yīng)用廣泛的情況下,足以證明此引擎具備商業(yè)產(chǎn)品使用價(jià)值。通俗的講,別人能用這玩意做出游戲,你也能。所以針對(duì)這兩方面進(jìn)行一下粗略的分析。
我對(duì)國(guó)外的HTML5游戲市場(chǎng)完全不了解,這個(gè)市場(chǎng)分析的東西太大,不好做評(píng)價(jià)。就分析一下國(guó)內(nèi)的,簡(jiǎn)單看一下到底哪個(gè)引擎用的多。
我用了國(guó)內(nèi)比較火的HTML5游戲平臺(tái)新浪微博作為數(shù)據(jù)采樣基礎(chǔ),一個(gè)人實(shí)在精力有限,不可能做的完整。由于客戶端對(duì)游戲地址進(jìn)行了加密,無(wú)法直接獲取。所以用了一些調(diào)試工具來(lái)看游戲網(wǎng)頁(yè)的標(biāo)記,以此判斷游戲到底使用什么引擎制作。
最終統(tǒng)計(jì)結(jié)果如下:
游戲名稱 | 引擎 | 游戲名稱 | 引擎 | 游戲名稱 | 引擎 |
---|---|---|---|---|---|
CEO養(yǎng)成計(jì)劃 | 純HTML5 | 全民把妹 | Egret | 鬼吹燈 | laya |
一夜成名 | 純HTML5 | 決斗西游 | Egret | 邊鋒斗地主 | cocos |
上吧主公(萌喵闖三國(guó)) | 純HTML5 | 呆呆忍者村 | cocos | 少女戰(zhàn)機(jī) | Egret |
三國(guó)魂 | Egret | 全民穿越之宮 | Egret | 蟲(chóng)蟲(chóng)大戰(zhàn) | createjs |
傳世霸業(yè) | cocos | 召喚師學(xué)院 | cocos | 我欲封天H5 | Egret |
傳奇世界 | Egret | 全民狂戳 | Egret | 萌戰(zhàn)姬 | Egret |
全力游戲 | Egret | 全民魔魔噠 | cocos | 我們的萌萌 | Egret |
全員加速中 | Egret | 戰(zhàn)神 | cocos | 藥水英雄 | cocos |
全民宮斗 | 純HTML5 | 全民首富 | 純HTML5 | 愚公移山 | Egret |
坦克風(fēng)云 | Egret | 無(wú)限穿越 | cocos | 覺(jué)醒吧MT | cocos |
大主宰 | cocos | 星愿城市 | cocos | 悟空歸來(lái) – 西游神傳 | Egret |
大俠歸來(lái) | Egret | 深海保衛(wèi)戰(zhàn) | Egret | 美人心計(jì) | Egret |
大大大掌門(mén) | Egret | 泡泡奧特曼 | Egret | 德州撲克H5 | Egret |
天天賺錢(qián) | Egret | 暴走大亂斗 | Egret | 經(jīng)典瑪麗h5 | Egret |
小鳥(niǎo)情人OL | 純HTML5 | 狂掛傳奇 | Egret | 少年,好功夫 | Egret |
少女H計(jì)劃 | Egret | 盜墓英雄 | Egret | 秘密魔法花園 | cocos |
少女H計(jì)劃2 | Egret | 神傳 | Egret |
一共找了50款游戲,如上面表格。50款引擎,使用純HTML5開(kāi)發(fā)的6款,使用Egret開(kāi)發(fā)的30款,Cocos2d-js的14款,laya的1款,createjs的1款。
統(tǒng)計(jì)結(jié)果如下:

不難看出,Egret 和 Cocos2D-js聯(lián)合瓜分了大部分市場(chǎng)。而Egret占比居然過(guò)半,達(dá)到58%。看來(lái)Egret在國(guó)內(nèi)HTML5游戲市場(chǎng)還是非常強(qiáng)悍的。
總結(jié)
- Three.js:作為老牌的3D庫(kù),它已經(jīng)有眾多案例,在PC多網(wǎng)頁(yè)3D中是目前不錯(cuò)的選擇。
- Phaser:文檔教程,和案例方面都很不錯(cuò),功能也算的上豐富。非常適合獨(dú)立游戲開(kāi)發(fā)和小團(tuán)隊(duì)使用。
- Pixi.js:作為渲染器,其渲染性能絕對(duì)是非常優(yōu)秀的,游戲功能方面支持很差,適合極客程序員把玩。
- Egret:性能不錯(cuò),在工作流方面支持非常優(yōu)秀,適應(yīng)中度和重度HTML5游戲開(kāi)發(fā),有較多商業(yè)項(xiàng)目驗(yàn)證,非常適合商業(yè)團(tuán)隊(duì)使用。
- enchant.js:性能偏差,不太推薦。
- craftyJS:文檔教程等方面不太完善,很難找到對(duì)應(yīng)技術(shù)支持,不推薦。
- Turbulenz:性能極佳,但捆綁其自身業(yè)務(wù),不太適合國(guó)內(nèi)市場(chǎng)。
- cocos2d-js:老牌引擎,其性能在排名中居中,工作流支持相對(duì)完整,推薦。
- PlayCanvas:重度3D游戲開(kāi)發(fā)引擎,本文不對(duì)3D做推薦。
- melonJS:性能不理想,不推薦。
- Quintus:不支持WebGL模式,性能較差,不推薦。
- Hilo:阿里前端團(tuán)隊(duì)作品,偏向于前端開(kāi)發(fā)工程師,與游戲?qū)I(yè)開(kāi)發(fā)距離較大,推薦做HTML5營(yíng)銷小交互的使用。