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

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

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

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

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

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

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

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

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

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

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

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

ResDepot:這是個小工具,用來配置游戲資源加載表。如果游戲資源多的話,用這個小工具拖拽一下就完成了。
TextureMerger:一個紋理合并的小工具,功能有點像TexturePacker。
DragonBones Pro:針對Egret中骨骼動畫解決方案提供的DragonBones動畫編輯器。

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

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

melonJS
melonJS除了源碼庫以外,也沒有提供任何工具支持。但在其官方主頁中,包含幾個其他編輯器的連接。比如著名的Tiled地圖編輯器等。
Quintus
Quintus沒有提供任何工具支撐。
Hilo
Hilo沒有提供任何工具支撐。
總結(jié)
結(jié)果并不出乎意料,對于開源游戲引擎來講,維護庫就是耗費作者很大一部分精力,更何況去制作編輯器之類的軟件產(chǎn)品。很多引擎都會依賴一些比較流行的第三方工具,例如Tiled、TexturePacker等等。雖然可以實現(xiàn)功能,但整個工作流搭配起來還是多多少少會有一些問題。只有Egret和Cocos2D-js提供了相關(guān)可視化編輯工具。而這兩對于工作流的理解則完全不同。從產(chǎn)品中不難看出,Cocos2D-JS更像Unity3D,提供一個大而全的軟件給開發(fā)者用。Egret則是什么角色用什么工具,將產(chǎn)品按照角色劃分,針對不同角色和開發(fā)流程中的各個環(huán)節(jié)進行產(chǎn)品設(shè)計。
相對來說,Egret的這種方式使得每個工具更加垂直,能夠做的功能也更加深入,不會讓工具顯得臃腫。而Cocos Creator則力求完整,一個軟件解決所有事情。
性能
性能測試上,我只針對2D游戲引擎做了一個渲染壓力測試。
測試內(nèi)容為同屏渲染對象數(shù)量相同的情況下進行幀頻數(shù)據(jù)對比,為了保證測試的公平性,我使用同一臺電腦,相同版本的Chrome瀏覽器進行測試,游戲場景尺寸均為800*600,顯示的圖片也為同一張。每個引擎進行同屏5000、10000、20000個顯示對象渲染。
其中craftyjs引擎渲染出現(xiàn)問題,這里不作數(shù)據(jù)對比。
Quintus引擎不支持WebGL渲染模式,因此這里頁不作數(shù)據(jù)對比。
Phaser渲染內(nèi)核使用Pixi.js,因此Phaser渲染數(shù)據(jù)參考Pixi.js結(jié)果。
所有引擎編寫的代碼大致相同,開始做for循環(huán),創(chuàng)建定量顯示對象,然后在循環(huán)中對每個顯示對象做旋轉(zhuǎn)操作。
測試代碼如下:
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(); }
我的電腦配置如下:

最終測試結(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é)論
按照上述測試方法,我們可以對引擎性能排名做一個大致排列:
第一名:Pixi.js 和 Turbulenz
第二名:Egret
第三名:Cocos2d-js
第四名:Hilo
第五名:enchant.js
第六名:melonJS
最后放出一張測試時效果圖

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

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