HTML5 游戲引擎深度測評

MarkusWolke 9年前發布 | 82K 次閱讀 HTML5 游戲引擎

 

最近看到網上一篇文章,標題叫做《 2016年 最火的 15 款 HTML5 游戲引擎 》。目前針對HTML5游戲的解決方案已經非常多,但誰好誰差卻沒有對比性資料。特意花了幾天時間,針對文章中出現的12款免費開源引擎做了一次相對完整的對比分析,希望能對大家有所幫助。

針對技術類產品對比,通常有多個維度進行對比,不僅僅是技術層面,還有許多非技術層面的內容會影響我們的使用結果。本文從如下幾個維度進行多重對比。

  1. 2D與3D

  2. 編程語言

  3. 設計理念&功能

  4. 工作流

    性能

  5. 學習資料

  6. 商業應用

2D與3D、編程語言對比

2D與3D

游戲領域中,最直白的一種分類方法便是2D與3D的區分。通常我們都會認為它們是游戲引擎領域兩類不同的產品。原文中提及的引擎確實是當下最為流行的HTML5游戲引擎。很多引擎屬于2D、3D通吃類型,我們通過一個表格進行對比。

編程語言

基于HTML5技術的游戲引擎,所需要的腳本必定是JavaScript,只有JavaScript腳本語言才能運行于瀏覽器中。但目前市場上,出現了很多JavaScript代替品,例如TypeScript、CoffeeScript、LiveScript等等。不同語言直接的定位不同,語言哲學也不盡相同。一些游戲引擎在語言選擇上也頗有意思。

結論

可以從表格中看出,下面三個引擎屬于2D和3D通吃類型。

  • Egret

  • Turbulenz

  • PlayCanvas

在Web游戲領域勝出的編程語言是JavaScript和TypeScript。但絕大部分HTML5游戲引擎還是采用JavaScript語言。只有三款引擎選擇支持TypeScript。其中Egret做的最為徹底,僅支持TypeScript,并未推出JavaScript語言版本。

從當前前端技術圈環境分析,未來可能很多前端框架或者引擎會推出響應的TypeScript語言分支,從AngularJS宣布將使用TypeScript開發開始,TypeScript在很大程度上被前端認可。不得不說微軟在開源圈這一仗打得漂亮。

設計理念&功能

架構設計是一門大學問,對于開源引擎架構的設計模式主要取決于作者的程序哲學觀點和產品定位。將設計思路和功能放在一起對比討論,比單獨功能討論更有參考意義。一個引擎的功能并非越多越好,功能應圍繞引擎定位而定,這樣的思路在一些引擎中體現尤為明顯,下面我們針對每個引擎一一分析。

Three.js

定位

Three.js項目創建時間是在2010年的4月24日,到目前位置,應該算是比較老牌的開源項目了。事實上Three.js定義并非一個游戲引擎。在Github主頁中,作者很明確的定義了Three.js的定位,叫做“JavaScript 3D library”。它僅僅是一個基于JavaScript語言的3D庫而已。當然,你可以用它來做任何事情,無論是游戲,還是炫酷的3D展示。

設計理念

Three.js在設計之處希望創建一個非常輕量級的3D庫,能夠幫助開發者快速搭建基于HTML5的3D內容。同時,通過暴露簡單的API,將3D內容的開發復雜性降至最低。

渲染環境上,Three.js支持WebGL和CCS3D兩種渲染模式。從當前使用量和標準普及程度來做分析看,開發者更加傾向于WebGL渲染方式。

功能

文本主要想對2D游戲引擎做深入分析,所有沒有對Three.js的功能與那些流行的3D引擎加以對比。

Pixi.js

定位

很多人第一眼看到Pixi.js官網,都會不自覺的認為這是一款游戲引擎。但在主頁中作者對于Pixi.js的定義為“2D WebGL renderer with canvas fallback”,翻譯為中文是一款依賴于canvas的WebGL渲染器。所以當你看到Pixi.js提供了為數不多的功能時,請不要驚訝,因為它只是一款渲染器。

設計理念

Pixi.js的設計理念很多程度來源于它的定位,只做渲染器,要把渲染功能做到最強。而這樣的定位,則會讓Pixi.js成為其他引擎的渲染內核。你經常能看到一些游戲引擎,或者產品都基于Pixi.js而開發。

最求極致的渲染性能是Pixi.js的首要任務,為了讓Pixi.js更加易于使用,作者在API設計上更加參考非常成熟的2D渲染架構 —— Flash,并且提供的API也盡量參考了ActionScript。

例如創建一個顯示對象,在Pixi.js中被封裝為PIXI.Sprite。如果需要顯示圖像,借助PIXI.PIXI.Texture紋理進行渲染數據填充。最終設置顯示對象的坐標,代碼看起來就像下面這樣。

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中的顯示架構完全參考Flash設計,所有顯示對象組合為一個樹狀數據結構,但內部已針對WebGL渲染方式進行過優化,上層使用起來和Flash并無太大差別。

功能

游戲引擎中的功能,我們可以細分非常多分類,一篇文章無法講解所有分類細節講解明白。我將所有功能做了一個二級分類,方便分析。

Phaser

定位

刻意將Pixi.js放在前面分析,因為Phaser本身并沒有自己的渲染核心。就像Pixi.js的定位不一樣,Phaser的定位是 "Desktop and Mobile HTML5 game framework",中為稱之為“桌面與移動端的HTML5游戲框架”。Phaser并不把自己定義為Engine,而是框架。所以,當你看到Phaser的功能設計和它的渲染內核時就不會經驗了。

設計理念

因為將自己定位為游戲框架,所以Phaser在游戲功能方面顯得相當全面,你能想得到的絕大部分功能Phaser已經替你實現了。在渲染方面,Phaser并沒有自己的渲染內核,而是直接引用了Pixi.js。這確實是個明智之舉,因為Pixi.js在渲染性能方面非常強悍。前面已經提及編程語言,游戲開發本身邏輯復雜,算法較多,Phaser提供對TypeScript的支持也是非常明知的。

架構方面,Phaser進行非常多的高度封裝。就顯示部分而言,如果你使用過Pixi.js就是發現,設計思路本身差別不大,但API使用起來則方便很多。Phaser為一準備好了游戲所需要的一切。當我們像創建一個游戲界面時,可以在Phaser初始化時針對不同階段進行定制。

var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update });

正向上面這行代碼,Phaser為我們定義了preload、create、update等方法,使用時只需要填寫callback函數即可。在資源加載時,Phaser會為你調用preload回調。 當畫面刷新時,可以調用update回調。

其他方面,信號和插件系統算是Phaser的最大特色了。

功能

Phaser功能眾多,但絕大部分應用其他第三方作為實現。

Egret

定位

Egret算是HTML5游戲引擎中的新起之秀,其定位已不單純為HTML5游戲引擎。官方將其定位為“游戲解決方案”,同時也并未過多提及HTML5。究其原因在于Egret不僅僅提供了一個基于HTML5技術的游戲引擎,更是提供了原生打包工具和眾多周邊產品,使其成為“解決方案”。

設計理念

這里單獨分析Egret Engine這個產品,其語言使用TypeScript,有2D和3D版本。在架構設計上,同Pixi.js一樣,參考了Flash成熟的2D架構體系。API方面,也參考了ActionScript。不僅如此,由于TypeScript的緣故,在事件系統中,也仿照ActionScript實現了addEventListener這樣的事件注冊機制。

內核方面,Egret Engine采用了模塊化的設計。這樣可以將不同的功能進行解耦。更加有趣的是,Flash中引以為傲的自動臟矩形技術在Egret Engine中也被實現。在canvas模式下,臟矩形會是渲染性能得到提升,比其他引擎更加有優勢。

如果你會Flash,那么Egret Engine對你來說不需要過多的學習即可上手。

功能

Egret Engine由于模塊化設計的原因,將不同功能放到了不同模塊中。這些模塊以庫的形式提供,下面表中是所有支持模塊的總和,但不含平臺API部分,例如微信API的封裝。

enchant.js

定位

enchant.js并非一個引擎,而是一個框架。同時,enchant.js也不僅僅用于游戲,還可以用于app。

設計理念

鑒于支持游戲開發和APP開發,這個框架必定會顧全一些東西,不能在游戲方面放開手腳。架構設計上,沒講所有的元素全部按照OOP方式設計,內部使用實踐驅動,并有效的結合了異步處理。游戲方面則僅僅對動畫相關功能做了支持。enchant.js框架提供了一套插件機制,你可以將使用到的功能模塊作為插件注入到enchant.js框架中。

enchant.js還特意提供了一個在線的圖像庫,方便開發者免費使用其中的素材。當從游戲效果來看,以小游戲居多。

功能

enchant.js框架自身提供的功能非常有限,如果需要其他功能,必須自己擴展或者尋找響應的插件。

craftyJS

定位

craftyJS將自己定義為針對JavaScript游戲的框架。

設計理念

由于框架的定位,craftyJS在設計上提供了一些系統級別支持,例如將canvas和Dom兩種渲染方式封裝為同一套API,盡量小的文件體積,實體組件系統,顯示對象封裝,碰撞檢測,事件系統,還有很多功能組件模塊。所有的模塊都依賴于實體組件系統的設計。

在實際測試中,craftyJS在API上的設計思路也是使用起來最為不舒服的一個。

功能

Turbulenz

定位

Turbulenz引擎實際上是為自己的游戲渠道中的游戲提供的游戲引擎。因為和自身渠道綁定,所以在引擎中提供了很多low level API。借助這些底層API,可以呼叫Turbulenz游戲渠道中的一些系統級別功能。

設計理念

由于Turbulenz引擎更多的為自己設計,更多的提供runtime支持,從嚴格意義上將,Turbulenz引擎不算是純正的HTML5游戲引擎。為了滿足其自身渠道的需求,Turbulenz引擎力求增加更加完整的功能,同時提高其運行性能。

功能

由于Turbulenz對很多功能做了擴展,同時推出Low Level API和 High Level API。這里不再對其中龐雜的系統進行功能分析,大家如果有興趣可以到其官網查看。

cocos2d-js

定位

cocos2d-js是喊著Cocos2D-X的金鑰匙出身的,它僅僅是Cocos2D-X的一個HTML5實現的分支。

設計理念

cocos2d-js和Cocos2D-X的設計理念相同,你能夠看到所有的API以及語法都完全參考Cocos2D-X。國內對于Cocos2D-X已經非常了解,這里就不做過多介紹。

功能

cocos2d-js的功能提供的相當完整,你在游戲中需要的功能幾乎都能夠找到。

PlayCanvas

定位

PlayCanvas主要用于3D渲染,本文還是以2D討論為主,對PlayCanvas的分析就不做過多分析。

melonJS

定位

melonJS是一個輕量級的HTML5游戲框架,并且通過插件機制擴展其功能。

設計理念

melonJS在所有的功能設計上都是輕量級的,你可以看到很多功能,并且在此基礎之上搭建你自己所需要的功能模塊。melonJS對于Tiled Map支持非常好,在兼容性方面也是melonJS關注的重點。

功能

Quintus

定位

Quintus將自己定位為簡單好用的JavaScript游戲引擎,同時支持移動和PC端。

設計理念

Quintus設計為模塊化和輕量化,盡量使用簡潔友好的JavaScript語法。在JavaScript的API結構設計中,盡量使用標準的OOP模式。Quintus還借助了jQuery,并通過jQuery插件實現事件和一個選擇器的語法。語言設計層面上Quintus沒有設計限制使用傳統的繼承,這使得其中得組件模型更加容易被復用。

功能

Quintus自身并不支持WebGL,同時提供的功能也較少,在Github中排名也很靠后。

Hilo

定位

Hilo這個引擎來源于阿里前端團隊,從官網的主頁上看,這個引擎的定位比較模糊。Hilo作為一個跨終端的互動小游戲解決方案,同時有稱綜合解決方案。從它的演變來看,Hilo屬于阿里前端在實踐總總結出來的一套工具庫。整體引擎并非最初有計劃設計構想。

設計理念

從Hilo支持的特性上看,Hilo的設計思路更加偏向與前端開發者,而非游戲開發者。Hilo提供了多種模塊范式的包裝版本,實際上在滿足不同前端開發者習慣。這些特性完全是前端工程師所偏好的內容,對于游戲來講,這些內容可能優先級并非最高,作為阿里內部團隊的常用引擎,對于阿里來說應該非常合適,應用場景做簡單營銷互動小游戲足以。

功能

Hilo功能相對比較簡單,對于游戲開發來說,缺失功能較多。

工作流

對團隊開發來講,工作流搭建是非常重要的,我個人比較看重這點。如果是小型團隊或者個人開發者可能對此需求并不大。當項目規模變大時,一個好的工作流會事半功倍。

因為引擎的功能不同,所以涉及的工具也會有所差異,這里就不再做表對比了。

Three.js

3D并不在本篇文章的討論范圍之內,同時Three.js也并非游戲引擎,不存在游戲開發工作流一說。這里簡單介紹一下Three.js所提供的在線編輯器。

Three.js提供的在線編輯器應該是基于Three.js開發的,功能不多,但相當小巧。

Pixi.js

Pixi.js作為一個渲染器,其工具支持也是相當清爽,除了一個程序庫之外,沒有提供任何工具。

Phaser

Phaser和Pixi.js一樣,沒有提供任何工具支持,在其官網上只是推薦了兩個代碼編輯器。還提供了一個簡單的在線代碼編輯器。

Egret

Egret提供的工具非常多,也復合其解決方案的定位。在Egret整個體系下你可以看到如下工具支撐。

Egret Wing:Egret出品的一個IDE編輯器。在提供代碼編輯功能的同時,還內置可視化的UI編輯器。與Egret Engine中的GUI、EUI框架配合使用。

ResDepot:這是個小工具,用來配置游戲資源加載表。如果游戲資源多的話,用這個小工具拖拽一下就完成了。

TextureMerger:一個紋理合并的小工具,功能有點像TexturePacker。

DragonBones Pro:針對Egret中骨骼動畫解決方案提供的DragonBones動畫編輯器。

Egret Inspector:一個基于Chrome瀏覽器的插件,可以針對Egret游戲進行調試。

Egret iOS & Android Support:這兩個東西可以將你的HTML5游戲打包成原生APP。

還有一些其他的工具,但定位與游戲開發不同,有興趣可以去它的官網看。

從上面的分析看出,Egret在工作流的支持上做的還是非常完成的,從Wing的代碼編寫,到ResDepot和TextureMerger的資源整合,再到Inspector調試,和原生打包。游戲開發過程中的每個環節基本都有工具支撐。

enchant.js

enchant.js 沒有提供任何工具支撐,在官網中也沒有任何相關支持工具的介紹。

craftyJS

craftyJS也沒有提供任何工具支撐,僅僅是一個開源代碼庫。

Turbulenz

Turbulenz在你下載的目錄中包含了很多工具,大部分與格式轉換相關。所有工具均為命令含小工具,沒有提供任何可視化操作軟件支持。

cocos2d-js

Cocos2d-js近年來變化很大,但對于JS這個分支的支持卻少之又少。前一段時間新出了一個工具叫做Cocos Creator。我沒有具體使用過,但看截圖仿佛有Unity3D的影子。從介紹中看,應該對游戲支持還是不錯的,編輯方面目前還欠缺。

PlayCanvas

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

melonJS

melonJS除了源碼庫以外,也沒有提供任何工具支持。但在其官方主頁中,包含幾個其他編輯器的連接。比如著名的Tiled地圖編輯器等。

Quintus

Quintus沒有提供任何工具支撐。

Hilo

Hilo沒有提供任何工具支撐。

總結

結果并不出乎意料,對于開源游戲引擎來講,維護庫就是耗費作者很大一部分精力,更何況去制作編輯器之類的軟件產品。很多引擎都會依賴一些比較流行的第三方工具,例如Tiled、TexturePacker等等。雖然可以實現功能,但整個工作流搭配起來還是多多少少會有一些問題。只有Egret和Cocos2D-js提供了相關可視化編輯工具。而這兩對于工作流的理解則完全不同。從產品中不難看出,Cocos2D-JS更像Unity3D,提供一個大而全的軟件給開發者用。Egret則是什么角色用什么工具,將產品按照角色劃分,針對不同角色和開發流程中的各個環節進行產品設計。

相對來說,Egret的這種方式使得每個工具更加垂直,能夠做的功能也更加深入,不會讓工具顯得臃腫。而Cocos Creator則力求完整,一個軟件解決所有事情。

性能

性能測試上,我只針對2D游戲引擎做了一個渲染壓力測試。

測試內容為同屏渲染對象數量相同的情況下進行幀頻數據對比,為了保證測試的公平性,我使用同一臺電腦,相同版本的Chrome瀏覽器進行測試,游戲場景尺寸均為800*600,顯示的圖片也為同一張。每個引擎進行同屏5000、10000、20000個顯示對象渲染。

其中craftyjs引擎渲染出現問題,這里不作數據對比。

Quintus引擎不支持WebGL渲染模式,因此這里頁不作數據對比。

Phaser渲染內核使用Pixi.js,因此Phaser渲染數據參考Pixi.js結果。

所有引擎編寫的代碼大致相同,開始做for循環,創建定量顯示對象,然后在循環中對每個顯示對象做旋轉操作。

測試代碼如下:

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; this.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();
}

我的電腦配置如下:

最終測試結果

結論

按照上述測試方法,我們可以對引擎性能排名做一個大致排列:

第一名:Pixi.js 和 Turbulenz

第二名:Egret

第三名:Cocos2d-js

第四名:Hilo

第五名:enchant.js

第六名:melonJS

最后放出一張測試時效果圖

學習資料

通常情況下,我們都會選擇一個資料較全的產品進行學習使用,畢竟使用過程中會遇到各種各樣的問題。現在游戲引擎的文檔,討論組等都已經成為了產品標配。下面這個表格就對各個引擎的這些“標配”做一個對比。

從上面對比表格可以看出,絕大部分引擎在文檔教程方面做的還是比較深入的,但完成程度不同。大部分都為英文文檔,對于國內的開發者來說可能學習起來成本略高。其中兩個支持中文的引擎Egret、Hilo均為國人產品,這兩款引擎在文檔方面,Egret做的相當優秀,開發者可以從它的edn.egret.com中查閱大量中文資料。 結論

在學習難度上,Egret算是最為簡單的,無論從完整度還是中文普及度上。

商業應用

這部分對比是在商業產品應用中的占比情況。一個引擎被商業產品應用廣泛的情況下,足以證明此引擎具備商業產品使用價值。通俗的講,別人能用這玩意做出游戲,你也能。所以針對這兩方面進行一下粗略的分析。

我對國外的HTML5游戲市場完全不了解,這個市場分析的東西太大,不好做評價。就分析一下國內的,簡單看一下到底哪個引擎用的多。

我用了國內比較火的HTML5游戲平臺新浪微博作為數據采樣基礎,一個人實在精力有限,不可能做的完整。由于客戶端對游戲地址進行了加密,無法直接獲取。所以用了一些調試工具來看游戲網頁的標記,以此判斷游戲到底使用什么引擎制作。

最終統計結果如下:

一共找了50款游戲,如上面表格。50款引擎,使用純HTML5開發的6款,使用Egret開發的30款,Cocos2d-js的14款,laya的1款,createjs的1款。

統計結果如下:

不難看出,Egret 和 Cocos2D-js聯合瓜分了大部分市場。而Egret占比居然過半,達到58%。看來Egret在國內HTML5游戲市場還是非常強悍的。

總結

  1. Three.js:作為老牌的3D庫,它已經有眾多案例,在PC多網頁3D中是目前不錯的選擇。

  2. Phaser:文檔教程,和案例方面都很不錯,功能也算的上豐富。非常適合獨立游戲開發和小團隊使用。

  3. Pixi.js:作為渲染器,其渲染性能絕對是非常優秀的,游戲功能方面支持很差,適合極客程序員把玩。

  4. Egret:性能不錯,在工作流方面支持非常優秀,適應中度和重度HTML5游戲開發,有較多商業項目驗證,非常適合商業團隊使用。

  5. enchant.js:性能偏差,不太推薦。

  6. craftyJS:文檔教程等方面不太完善,很難找到對應技術支持,不推薦。

  7. Turbulenz:性能極佳,但捆綁其自身業務,不太適合國內市場。

  8. cocos2d-js:老牌引擎,其性能在排名中居中,工作流支持相對完整,推薦。

  9. PlayCanvas:重度3D游戲開發引擎,本文不對3D做推薦。

  10. melonJS:性能不理想,不推薦。

  11. Quintus:不支持WebGL模式,性能較差,不推薦。

  12. Hilo:阿里前端團隊作品,偏向于前端開發工程師,與游戲專業開發距離較大,推薦做HTML5營銷小交互的使用。

原文: HTML5游戲引擎深度測評

 本文由用戶 MarkusWolke 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!