本文作者: Shopee Games 前端團隊。
摘要
Shopee Games 團隊致力於豐富 Shopee 電商內的互動性和娛樂性,讓使用者在購物之餘獲得更多愉悅感,同時遊戲也能為 Shopee 帶來持續的活躍使用者和更多的優惠券發放渠道。在這個背景下,從遊戲誕生之初,我們希望遊戲足夠輕量,而且能夠快速迭代,持續給使用者提供多種多樣的遊戲體驗,同時又不會對 Shopee App 的體積造成較大影響。因此,我們需要選擇合適的遊戲引擎,並打造適合 Shopee Games 的工具鏈。
本文將介紹 Shopee Games 團隊如何選擇遊戲引擎,如何擴充套件遊戲引擎以提高生產效率,如何讓遊戲開發流程和成熟的前端工程化體系結合,實現遊戲規範化和研發質量的提升。Shopee Games 是內嵌在 Shopee App 的遊戲,所以對於有同樣內嵌遊戲需求的業務團隊,本文總結的經驗會有一定借鑑意義。
1. 遊戲引擎選型
Shopee Games 當前以休閒類遊戲為主,為了減少對 Shopee App 體積的影響,技術選型上會偏向於 H5 遊戲。而如何選擇 H5 遊戲引擎,我們主要考量以下幾個方面的因素:
- 2D 還是 3D 遊戲?
- 是否對開發友好?包括是否支援 TypeScript、文件是否完善、研發流程是否適合以開發為主導。
- 效能和相容性如何?
- 官方工具鏈是否完善?
- 是否開源?
- 是否有成功的遊戲案例?
- 官方是否有客服支援?
- 官方是否有持續更新?
首先,我們的休閒類遊戲主要為 2D 遊戲,所以我們先聚焦在針對 2D 設計的遊戲引擎上。雖然 3D 引擎可以通過正交視角來實現 2D 效果,但渲染效能和輕量化都不如專門的 2D 引擎,所以我們先把 3D 為主的引擎排除掉,例如 Unity3D、LayaBox、Three.js、Babylon.js。而 2D 引擎,國內主要有老一些的 lufylegend.js、Cocos2d-JS 和持續更新的 Egret、Cocos Creator,國外有 Phaser/Pixi 和 CreateJS。
接著,從可持續性、效能方面考慮,可以先把較老的 lufylegend.js、Cocos2d-JS 排除。而 CreateJS 實際並不是一個完整的遊戲引擎,它更接近於一個精簡的渲染引擎,缺少整體的工具配套,難以支援大型遊戲,也排除。
那麼,最後我們重點對比 Egret、Cocos Creator 和 Phaser。Phaser 的渲染引擎就是 Pixi,後續用 Phaser 代表這兩者。
以上三款遊戲引擎都支援 TypeScript 和 WebGL,效能差異不大。對於 Shopee Games 團隊而言,Egret 有較大優勢:
- Egret 支援 canvas 模式,因此東南亞市場中的一些低端手機使用者也能夠執行我們的遊戲;
- Egret 的理念是面向開發者的,而我們團隊有較強的研發能力,以開發者為導向能夠讓整個遊戲效能更好;
- 在工具鏈上,Egret 有自研的龍骨動畫和編輯器,非常適合我們的遊戲開發。
因此,綜上所述,我們選擇 Egret 作為主流引擎,並在 Egret 的生態基礎上,持續優化和打造能夠提高遊戲開發效率的工具鏈。
2. Egret 引擎優化和公共庫
2.1 Egret 引擎優化
Egret Engine 是白鷺時代研發的遵循 HTML5 標準的開源遊戲引擎,包含 2D/3D 渲染核心、EUI 體系、音訊管理、資源管理等遊戲引擎的常用模組。
目前我們使用 Egret Engine 開發了 Shopee Candy、Shopee Pet、Shopee Fruit、Shopee Link 這四款遊戲,在專案開發和迭代過程中,我們發現官方引擎存在一些問題,無法完全滿足業務需求和效能標準。於是,我們對 Egret 引擎做了定製開發,下文稱之為“定製化引擎”。
2.1.1 效能上報
針對遊戲的一些資料指標,如 FPS、DrawCall、First Paint、GPU Size 等等效能指標進行上報。
上報流程如下:
通過分析上報的遊戲效能資料,我們能更好地分析效能瓶頸,從而有側重性地提升遊戲效能。其中,涉及到的詳細效能指標如下:
2.1.2 效能優化
我們在官方引擎基礎上針對效能做了一些優化,幫助開發人員提升遊戲效能。
靜態合圖
在開發過程中將散圖合成一張大圖的圖集,達到降低 DrawCall 的目的。
動態合圖
在專案執行時,動態地將貼圖合併到一張大貼圖中。當渲染一張貼圖的時候,動態合圖系統會自動檢測這張貼圖是否已經被合併到了圖集(圖片集合)中。如果沒有,並且此貼圖符合動態合圖的條件,就會將此貼圖合併到圖集中。
動態合圖是按照渲染順序來選取要將哪些貼圖合併到一張大圖中的,這樣就能確保相鄰的 DrawCall 能合併為一個 DrawCall。
和前面的靜態合圖原理一樣,都是以合圖紋理代替碎圖紋理,從而減少 DrawCall。而動態合圖最大好處是提高了一些無法提前靜態合圖的場景,例如使用者的裝扮。
節點順序調整
引擎底層的效能優化,目的是保證相同紋理的渲染順序。例如在同級 addChild 時,如果原始順序為 img1>text>img1
,引擎能自動優化成 img1>img1>text
,降低 DrawCall。
DrawCall 優化工具開啟
遊戲 Main 函式開啟 Benchmark.init(null,null,true)
;或者 Benchmark.optimizeDc
設為 true 即可。
2.1.3 引擎瘦身
官方引擎預設包含所有模組,其中有一些在我們的實際專案中使用不到。因此,為了減少引擎包體積大小,需要剔除掉用不到的程式碼,例如:
- Native 程式碼;
- Runtime 程式碼;
- WX 等小遊戲端相容程式碼;
- KTX 紋理相關程式碼;
- ETC Loader 程式碼。
修改前後對比:
最終,遊戲前端 JS 載入量共減少 16KB,約 7%。雖然這個體積看起來很小,但對於部分網路較差的地區,少量的體積優化也是有價值的。
2.1.4 Bug 修復
對於專案遇到的一些引擎層面的 bug,由於引擎官方可能會更新修復不及時,很多時候需要我們自己去修復。例如:iOS 14/15 渲染卡頓問題、龍骨庫渲染問題、網路以及音效問題等等。其中,我們解決 iOS 14/15 卡頓問題後,很榮幸貢獻了程式碼幫助 Egret 官方團隊解決這個問題。
2.1.5 API 增強
官方引擎的一些用法過於繁瑣,不夠友好,如設定節點寬高等。因此我們在官方引擎基礎上,擴充套件了方便快捷的 API,供大家使用。
2.2 公共庫
為了提高開發效率,避免大家重複造輪子,基於優化後的 Egret 引擎,我們做了公共庫的開發,封裝通用工具類、通用模組、通用 UI 元件等等。
2.2.1 工具庫
我們封裝遊戲中常用的一些工具庫:
- SoundUtil:音樂播放工具類,支援音效/背景音樂的播放/暫停/倍數播放等;
- DragonUtil:龍骨工具類,負責龍骨動畫的建立/銷燬等,隱藏龍骨建立細節,簡化龍骨動畫使用難度;
- ResUtil:遊戲資源管理類,方便開發者載入/釋放遊戲資源;
- SmartEvent:封裝的訊息通知類庫,方便大家使用,便於模組之間的解耦,包含自定義事件/UI 事件的監聽和移除;
封裝工具庫是為了降低開發難度,以及避免不同團隊重複造輪子。目前已在 Shopee Games 的四款 Egret 遊戲中使用,平均節約人力 2 周以上。
2.2.2 基礎 UI 元件
我們對 Egret 基礎元件進行了擴充套件,並提供了生命週期等一系列鉤子函式,降低開發難度,提升開發效率;同時,提供了一些各專案通用的元件,如:分享介面/好友介面/小怪獸彈窗等公共 UI 元件。
Egret 基礎元件擴充套件
我們為 UI 元件提供了一些生命週期的鉤子函式方便遊戲業務使用,開發者實現每個 UI 類時不必再單獨實現事件監聽和移除。同時,內建的事件管理也避免了開發者可能因開發遺漏而導致的記憶體洩漏問題。
具體的鉤子函式如下:
2.3 定製化引擎同步更新
隨著定製化引擎的修改越來越多,隨之而來的問題是:如果官方引擎更新了,我們怎麼快速合併官方引擎版本?
這裡採用的方案是 git 雙 remote 的方案,流程圖如下:
詳細步驟如下:
- 為了表示方便,我們把 Egret 引擎開源庫定義為 A,我們自己的定製化引擎倉庫為 B;
- 通過 git clone B ,拉取修改專案 B;
- 通過 git remote add A repository,以及 git fetch A,增加 A 遠端並獲取 A 的倉庫資訊;
- 假設 B 的開發分支是 dev,切換到此分支;
假設我們需要合併的是 A 的一個 tag,如 v5.4.0,使用 git merge v5.4.0--allow-unrelated-histories
,強制合併。
由於需要同步源框架專案程式碼,我們的改動會受到一些限制,否則每次合併都會有重複的工作量:
- 儘量不要重新命名或者刪除原本的檔案,或者改動程式碼裡面的函式及變數名;
- 如果需要擴充一個類的功能,儘量採用原型鏈擴充的形式;
- 自定義內部工具類可以內部自行定義,只要不重名即可;
- 行內程式碼儘量採用增加的模式,儘量不改動原本的程式碼;
- 有些庫程式碼會增加很多渠道相容的程式碼,我們可以適當減少,合併時會基於從共同祖先分析改變的機制,因此不會每次都要 diff。
通過以上方案,我們就可以實現官方倉庫和定製化引擎的快速同步。
3. 遊戲研發工程化
雖然 Egret 引擎能滿足 Shopee Games 的基本業務需求,官方也提供了一系列工具來滿足開發者的開發需求。但在使用 Egret 引擎的過程中,我們還是遇到了以下一些痛點:
- 缺乏模組概念:採用預設的 TypeScript 方式編譯,不支援檔案頂層 import 和 export,所有編譯檔案內容被視為全域性可見,容易造成變數汙染以及安全問題;
- 無法使用 npm:業務專案根目錄下不支援 package.json 檔案,不支援模組化的第三方庫;
- 缺乏工程化方案:沒有提供工程化的相關方案,如程式碼審查、單元測試等,專案也無法輕易接入常規的 Web 前端工程化方案;
- 部署流程複雜:程式碼編譯工具依賴於官方工具,沒有提供命令列版本,無法在伺服器上單獨部署。
顯然 Egret 工程無法滿足我們的工程需求。即便現在的 Web 前端工程化技術十分成熟,我們仍處於石器化時代,因此決定把 Egret 工程前端工程化。
3.1 Egret 前端工程化
3.1.1 支援根目錄 package.json
package.json 檔案可以說是目前前端專案必備的一個檔案,Egret 引擎起家比較早,當時的前端工程化還沒有那麼成熟,Egret 引擎的構建是官方自己寫的一套構建系統。
不支援根目錄下 package.json 檔案,很多事情也很難執行下去,還好 Egret 引擎的構建工具程式碼也是通過 JS 編寫,而且跟引擎程式碼一樣開源。
通過原始碼斷點除錯,我們發現 Egret 專案不支援根目錄下 package.json 的原因是:Egret 構建的時候,通過判斷根目錄下是否存在 package.json 來區分工程專案和庫專案,從而使用不同的構建流程,構建出不同的產物。
為了做到最小化的改動,且也能支援工程專案根目錄下存在 package.json,我們把構建專案的判斷修改為判斷 package.json 內自定義欄位的值,來區分是否為工程專案。
支援根目錄下存在 package.json,後續的一些工程化改造就比較容易進行下去了。
3.1.2 引擎 npm 包
官方構建依賴於本地機器上的構建工具,每次的部署釋出,都需要在本地構建完成後再上傳到伺服器上,與 Shopee 業務的部署規範和流程不太相符,並且嚴重阻礙了專案快速迭代的節奏。
為了使構建能夠支援在伺服器上單獨部署,我們把定製化引擎的程式碼進行改造和封裝,釋出成一個 npm 包的形式,專案依賴從一個本地的構建工具變成 npm 包。
"dependencies": {
"@egret-engine/egret-core": "1.6.2-alpha.1",
}
npm 包主要包含兩部分:
- build 目錄:引擎相關的庫檔案;
- tools 目錄:構建編譯相關工具。
釋出成 npm 不僅使得專案的編譯執行脫離本地環境,也能更好地去做專案的版本管理。但是僅釋出成 npm 包是不夠的,還需要結合以下的 Webpack 打包構建才能達到我們的目的。
3.1.3 Webpack 打包構建
為了支援模組化編譯以及在伺服器上單獨部署,我們選擇了成熟的 Webpack 構建方案接入到 Egret 專案中。
改造 Egret 專案構建前,首先需要分析一下 Egret 專案的依賴以及構建產物:
*.js
:程式碼構建產物。*.ts
:TypeScript 業務程式碼檔案。res
:專案資原始檔。例如:圖片、音訊、JSON 檔案等。egret libs
: Egret 專案依賴模組,即相關的 JS 庫檔案。*.exml
:Egret 特有的標籤語言檔案型別,用作 UI 佈局,可編譯成 JS 檔案和 JSON 檔案。
官方的構建類似於 gulp ,按照一定的順序執行每個任務。雖然官方也提供了自定義任務外掛的方式,讓開發者自定義構建流程,但這都需要開發者重新去開發,比較耗費人力。
exml 檔案型別是 Egret 引擎特有的檔案型別,目前前端生態沒有相關的解析編譯工具;res 檔案處理也沒有必要重新造輪子,所以我們沿用官方的工具,封裝到 @egret-egine/egret-core/tools
上,作為構建工具的一個依賴。
而 egret libs 依賴處理和 *.ts 程式碼編譯,我們都能在前端生態上找到更好的方案,根據需求使用即可。
通過 Webpack 去打包 Egret 專案,構建依賴來源於 npm,這樣就可以脫離本地環境,直接在伺服器上部署構建。而且產物也跟官方打包產物保持一致,做到良好相容。
3.1.4 工程化配置
經過以上改造,其實 Egret 工程專案跟普通的 Web 前端工程沒有太大區別,成熟的 Web 前端工程化方案在我們的專案中能得到很好的實踐,不僅能夠實現在伺服器上單獨部署,也能輕鬆接入質量把控的工具,例如 eslint、jest 等,提高程式碼質量。
3.2 Egret-Webpack-CLI 實現
在專案初期,我們主要根據業務和工程需求,基於 Egret 和 Webpack 搭建了專案腳手架模版。但在建立新專案和建立 demo 專案的時候,仍需要從倉庫 clone 模版倉庫下來,並且根據專案進行一定的人工配置。在目前的使用上看,問題不大,但仍然比較繁瑣,也有可能會遺漏一些配置,新建專案不能做到開箱即用。因此開發腳手架工具,能夠快速生成對應的模版專案。
3.2.1 CLI
一般腳手架工具主要分為 CLI 和 Template 兩部分。腳手架模版內容並沒有與 CLI 一起放到同一個倉庫,而是分別放到不同的倉庫進行管理和迭代。通過分離,可以確保兩部分獨立維護,不會互相干擾;模版配置或依賴更新只需要更新專案模版即可,無需影響 CLI 部分,導致重新發包。
參考其他腳手架的思路,模版作為獨立資源釋出到遠端倉庫上,然後執行的時候通過 CLI 工具下載下來,經過 CLI 的互動資訊,作為互動的輸入元資訊渲染專案模版。
終端執行 egret-cli 後,即可根據互動資訊,生成對應的 Egret 工程專案。
3.2.2 Template
由於我們需要對應不同的需求,且業務相關的配置較多,導致模版業務配置差異比較大,暫不能完全做到一個統一的模版。同時,為了保證一個模版內沒有冗餘的配置,我們做了區分,主要提供了 base、standard、Shopee、native 四種專案模版。
需要做小 demo 的時候,可以直接使用 base 模版,比較簡潔;如果需要研究跟業務有關的功能,可以選擇 Shopee 模版;如果是新專案的成立,則直接使用 native 模版。
3.3 最終 Egret 遊戲開發流程
Egret 專案與常規 Web 前端工程接軌,既解決了開發痛點,滿足了工程需求,也讓我們從石器時代正式步入工業時代,從開發到部署都有很好的工具去輔助執行,提高了程式碼質量和開發效率,新來的同學也能很好地上手專案。
成熟的 Web 前端工程不僅有利於我們的業務擴充套件,也賦予了專案更多的可能性。一些在前端很容易實現而在原來遊戲引擎比較難實現的功能,例如動態邏輯程式碼載入、多頁應用、Egret+React 混合頁面等,在我們的專案中也得到了很好的實踐。
4. 更多研發問題
4.1 iOS 稽核問題背景
在 Shopee Games 推出早期,使用者量和訪問量都不大,蘋果公司沒有著重針對 HTML5 版本的 Shopee Games 提出意見。但是,隨著 Shopee 業務不斷髮展,使用者量和訪問量持續增加,2021 年初,蘋果公司對 Shopee 內嵌的 HTML5 遊戲提出了意見,認為 Shopee App 違反了《App Store Review Guidelines》的 4.7 條款。
蘋果公司的審查條款原文是這樣的:
4.7.1 Software offered under this rule must:
- be free or purchased using in-app purchase;
- only use capabilities available in a standard WebKit view (e.g. it must open and run natively in Safari without modifications or additional software); and use WebKit and JavaScript Core to run third-party software and should not attempt to extend or expose native platform APIs to third-party software;
- be offered by developers that have joined the Apple Developer Program and signed the Apple Developer Program License Agreement;
- not provide access to real money gaming, lotteries, or charitable donations;
- adhere to the terms of these App Store Review Guidelines (e.g. do not include objectionable content); and
- not offer digital goods or services for sale.
歸納起來,包含以下幾點要求:
- 全免費的 H5 遊戲或使用蘋果支付;
- 僅使用 WebKit 自帶功能,不允許擴充套件,例如 JSBridge;
- H5 開發者需要加入蘋果開發者計劃;
- 不允許涉足金錢賭博,而且內容要符合其他審查條款一般限定。
而 Shopee Games 內嵌在 Shopee App 內,天生需要和 Shopee 深度結合,必然涉及 JSBridge (例如登入、跳轉電商店鋪)。並且,Shopee Games 還使用了 Shopee Coins 作為遊戲中的貨幣,而 Shopee Coins 並不是通過蘋果支付得到的,是使用者在電商購物中累積獲取的。從這兩個角度來看,Shopee Games 使用 HTML5 技術必然觸犯以上的蘋果審查條款。
我們參考了 Egret 引擎官方的建議,改變了 iOS 平臺上 Shopee Games 的技術架構,從原來的 HTML5 改為了 Native,使用的是 Egret Native Runtime。Egret 官方工具支援一鍵生成 iOS 工程併發布對應的 App 安裝包,這能夠滿足獨立遊戲的需求。但是 Shopee Games 需要內嵌在 Shopee App 中,並不是獨立的遊戲 App,所以無法直接簡單使用官方的一鍵釋出機制,我們需要進一步研究 Egret Native 的原理,從而和 Shopee App 做整合。
4.2 Egret Native 原理
分析 Egret Native 工具建立的 iOS 模板工程,可以發現:
- Egret Native Runtime 依賴一系列的系統庫和獨立封裝的 libEgretNativeIOS.a,主要核心邏輯和網路功能都在這個庫中。由於 Egret Native 並不開源,從模板工程無法得知這裡的具體實現;
- 固定以 App 根目錄的 assets 資料夾作為資源目錄,H5 版本的生成檔案需要固定存在此處,而且這裡只支援一個遊戲;
- 通過 libEgretNativeIOS 庫,可以建立相應的 EgretNativeIOS 例項和對應的 view。
雖然 Egret Native 並不開源,但根據官方文件,再結合模擬器斷點除錯分析,還是可以對 Egret Native 有進一步的發現。
Egret Native 遊戲架構包括三層:前端遊戲層、Egret Native Runtime 和 iOS Native 層。
- 前端遊戲層保持和 H5 版本的檔案內容一致;
- Egret Native Runtime 是核心的適配層,它使用 JSCore 對遊戲包內的 JS 檔案進行解析,搭建 JSBridge 實現 JS 和 Native 兩側的通訊。執行時渲染的方式和 Web 有所區別,Egret Native 有一個針對 Native 的 JS Polyfill 和 JS Engine 補充,並不是在 Runtime 層實現了全部瀏覽器功能;
- iOS Native 層,主要是管理 Egret Native Runtime 生命週期和管理檢視。
啟動 Egret Native 遊戲時,先從 iOS Native 層初始化 Egret Native 例項,並建立對應的遊戲 view,掛載到主介面上。然後,Egret Native 初始化 JS 引擎,繫結 JSBridge,讀取前端遊戲層的遊戲資源,解析 HTML 和 JS,呼叫 OpenGL 介面,最終顯示遊戲畫面。
4.3 Egret Native 和 Shopee App 結合
從模板工程來看,把 Egret Native 遊戲內嵌到 Shopee App 的方式是比較清晰的,把 libEgretNativeIOS.a 和其他必要的依賴庫新增到 Shopee App 專案工程中,再把遊戲包存放到 assets 目錄中,最後繫結必須的 Shopee JSBridge,供遊戲邏輯實現登入、支付、跳轉等操作,整個結合工作就完整了。
但是,在最終實現過程中,發現一些深層次問題,需要通過業務側的方式解決或規避。這些問題包括:
1)模板工程不支援多個遊戲
Shopee Games 包含多個遊戲,而上述 assets 目錄只支援存放一個遊戲的資源。並且 Egret Native Runtime,也就是上述的 libEgretNativeIOS.a 沒有開源,無法做針對性的修改。
最後,我們在官方的《熱更新方案說明》中,發現了 Egret Native 可以設定 preload 目錄路徑,而 preload 目錄內的資源優先順序比 assets 目錄高。
於是,我們可以在 Shopee App 內建多個遊戲,分別存放於一個單獨的目錄中,在啟動 Egret Native 前設定 preload 路徑為對應遊戲的路徑。Egret Native 啟動後會優先讀取 preload 目錄的資源來啟動遊戲,忽略後續 assets 的內容。
2)網路快取檔案無限增大
Egret Native Runtime 對網路請求做了快取,但沒有完善的清理機制,導致本地快取目錄會隨著遊戲下載的資源增多而無限增大。這部分需要在 Shopee App iOS Native 邏輯層面進行補齊。
3)部分第三方庫命名衝突
libEgretNativeIOS.a 自帶了一些第三方庫,例如 SocketRocket,而 Shopee App 也引入了這個庫,雙方都沒有對這個庫做別名處理,導致命名衝突編譯失敗。由於 libEgretNativeIOS.a 無法修改,只能在 Shopee App 業務層面自行修改 SocketRocket。
4)Egret Native 存在記憶體洩漏
由於在 Shopee App 中,Egret Native Runtime 需要反覆啟動和銷燬,只要 Egret Native Runtime 對物件、紋理處理稍有不當,都會引起記憶體洩漏。而對於 Egret Native 獨立遊戲來說,這個問題就不存在,因為每次關閉遊戲都是整個 App 的銷燬。這個問題已經反饋給 Egret 官方,但由於官方團隊不會專門針對我們的使用場景做處理,所以目前暫無進展。慶幸的是,這部分記憶體洩漏很小,暫時不構成大的問題。
通過解決上述一系列問題,最終我們實現了 Egret Native 和 Shopee App 的結合,能夠在 Shopee App 上執行多款自研遊戲。在蘋果稽核的角度,我們這個方式脫離了 Webkit,而且所有程式碼邏輯內建在提審的安裝包中,完全符合審查條款的要求。因此,方案上線後,Shopee App 和 Shopee Games 順利通過了 App Store 的稽核。
4.4 未來規劃
雖然 Egret Native 已經能夠結合在 Shopee App 中,但在持續運營半年後,我們發現 Egret Native 還是存在一些問題:
- Runtime 不開源,存在無法解決的問題;
- Runtime 只支援 Egret 遊戲,無法支援其他遊戲引擎。尤其是,Egret 引擎對 3D 遊戲開發來說,暫時還不是最佳選擇。
於是,我們正在籌劃更長遠的解決方案——自研的 Native Runtime,能夠同時支援多家 H5 遊戲引擎。
這個解決方案採用類似微信小遊戲的整體架構,但在 JS 層面會做進一步的封裝,方便 Shopee 內各個遊戲團隊快速接入。技術層面概要來說,就是 Native 基於 JS 引擎向 JS 側暴露對齊 WebGL 標準的介面和必要的 BOM 介面,從而普通 H5 遊戲引擎就可以無縫執行在瀏覽器和我們自研的 Runtime 上。
這個方案的好處有:
- 相容性好,能同時支援多家遊戲引擎;
- 方便存量 H5 遊戲轉移;
- 能利用各家引擎成熟的開發工具鏈。
但是,相應也存在劣勢:
- iOS 12 之後的版本正逐步放棄對 OpenGL 的支援;
- 由於相容多家引擎,難以使用新的圖形影像標準,例如 Metal、WebGL2、Vulkan。
目前 iOS 已經迭代到 15,OpenGL 和 WebGL 還是能夠平穩執行,而要支援多款 H5 遊戲引擎,WebGL 標準是無法繞過的,所以這些劣勢暫時不得不接受。另外,微信小遊戲也會面臨一樣的問題,相信未來會有蘋果官方的遷移方案,可能在 Metal 上層封裝類 OpenGL 的介面。
目前這套方案還在預研開發中,預計 2022 年內會實現並全面使用。之後不單是 Shopee Games,我們希望在更多的電商場景也能複用這套 3D/GPU 渲染的方案,給使用者創造更豐富多彩的互動玩法。
4. 總結
通過在多款 H5 遊戲引擎中做比較,Shopee Games 選擇了更適合業務特點和團隊人才特點 Egret 引擎。
在長期的業務開發運營中,我們為了更好地支援業務需求,對 Egret 引擎進行了定製化改造,包括 bug 修復和公共庫的修改。
優化引擎的同時,為了和官方倉庫保持同步,我們利用了 git 多 remote 倉庫的特性,實現了雙倉庫程式碼合併。
再進一步,為了複用成熟的前端 Webpack 構建體系和 CI/CD 流程,我們自研了 Egret-Webpack-CLI,把 Egret 遊戲從原來單機本地打包的模式,改為了伺服器 Webpack 打包,從而方便複用大量的優秀前端 npm 庫。上述這些創新,都給 Shopee Games 的研發帶來了重大提效。
在 iOS 稽核問題上,我們遇到了一些困難,最終通過深度整合 Egret Native 和 Shopee App,順利實現遊戲的 Native 化,通過了 App Store 的稽核。