
團隊原文:
efoxTeam/emp?github.com
一.背景
目前cocos2d游戲最主要的開發方式是通過官方提供的GUI圖形界面工具——creator
,通過 creator
開發者無需關注構建本身,只需通過界面操作即可對游戲代碼進行構建打包。但是這樣也存在著以下幾個問題:
- 構建閉源,導致開發者對項目構建無法定制化,假如編譯出來的代碼存在兼容性問題,那只能進入
creator
安裝目錄尋找對應的某個配置文件進行修改,這種侵入性的修改很有可能會引發不穩定性。 - 無法使用其他構建工具進行打包,意味著項目無法使用新的技術方案,只能局限于
creator
設定的框架之中 - 游戲組件在不同項目之間難以復用,組件通常包含了
prefab
、sprite
等資源,如何發布托管并在其他項目復用組件,簡單地通過creator
是無法做到的。通過 EMP微前端的方案 能從根本上解決這些問題
通過這些問題讓我們有了一種想法,有沒有可能通過其他構建工具打包的代碼,也能關聯到 creator
的項目中,這樣也能在creator cocos2d項目中引入EMP
,從而解決組件復用的問題
二. creator項目接入webpack模型
首先看看單一 creator
的開發過程,它會在本地服務開啟 7456
的端口服務,整個本地開發流程如下圖:

接入 webpack
和 emp
后的開發過程,首先 webpack
會通過 axios
抓去 creator
服務生成出來的 index.html
文件作為 template
,并開啟一個新的服務,并通過 devServer
將資源請求轉發回 creator
的端口服務,確保資源訪問正常,開發流程圖如下:

三. 接入流程
step1
全局安裝 @efox/emp-cli
,通過 emp init
初始化游戲種子工程,選擇 cocos2d
模版
yarn add --global @efox/emp-cli && emp init
step2
在根項目通過命令 yarn
安裝依賴
step3
安裝 creator cocos 開發工具 ,打開 cocosDashboard
, 導入剛剛的游戲模版項目,然后打開項目,下面是導入成功后的開發工具截圖;

復制開發工具上方提示的本地調試鏈接到瀏覽器上,呈現出來的界面如下,可以看到右方console出現報錯的情況,這是因為目前打開的只是 creator
開啟的本地服務,而項目引入了 webpack
構建的代碼,所以暫時會出現報錯的情況;

step4
進入項目根目錄,運行 yarn dev
瀏覽器會自動打開新端口服務,這個本地服務就是 webpack
代理 creator cocos
后的服務,通過下圖看到console已經沒有報錯了,并且界面上的 Hello World
擁有了漸變背景色,這個漸變背景色實際上就是一個 Game Component
,是通過 webpack
構建并注入到游戲項目中引入的;

ps: 必須先通過creator cocos
開啟項目,再運行 yarn dev
,因為 webpack
編譯時需要通過 axios
抓取 creator cocos
服務模版;
四. 項目代碼分析
emp-config.js
// cocos2d emp配置
const withCocos2d = require('@efox/emp-cocos2d')
const ip = require('ip')module.exports = withCocos2d(({config, env, empEnv}) => {// webpack本地服務端口const port = 9000const projectName = 'empCocos2dDemo'const host = ip.address()const publicPath = `http://${host}:${port}/`config.plugin('mf').tap(args => {args[0] = {...args[0],...{name: projectName,library: {type: 'var', name: projectName},filename: 'emp.js',// remotes: {// '@emp-game/base': 'empGameBase',// },exposes: {// 將當前項目的component expose出去給其他項目使用'./components': 'src/components',},},}return args})config.output.publicPath(publicPath)config.devServer.host(host)config.devServer.port(port)},{// creator開啟的服務端口creatorPort: 7456,// 引用基站資源鏈接empJs: [],},
)
src/index.ts
webpack
的代碼如何注入到 creator cocos
代碼中,靠的是 cc
這個全局變量,cc
變量是cocos2d引擎暴露在全局的,包含了全部的引擎方法;creator cocos
接入 emp
的關鍵點就是在 cc
全局變量上創建一個 EMP
屬性,這樣后續無論遠程組件模塊,抑或是本地構建的module, 都可以附值在 cc.EMP
上,從而在游戲代碼中引入;
cc
這個全局變量是cocos2d引擎暴露在全局的,這里也分為本地環境和生產環境的情況,這是因為本地環境cocos2d引擎腳本是同步加載的,而生產環境是異步的,這就是為什么下面代碼判斷了 window.boot
是否存在的情況,附值 cc.EMP
的操作是需要 cc
存在才能進行;
import Components from 'src/components'export type EMPData = {Components: typeof Components
}const EMP: EMPData = {Components,
}// 關鍵部分
// 生產環境 cocos2d腳本異步加載后 再執行window.boot
// 通過重寫 window.boot 在函數體內進行cc.EMP附值,再執行原函數,確保游戲代碼運行時 cc.EMP正常有值
if (window.boot) {const fn = window.bootwindow.boot = async function () {cc.EMP = EMPfn()}
} else {// 本地環境 直接附值cc.EMP = EMP
}
assets/Script/HelloWorld.ts
看回游戲代碼,了解游戲代碼是如何引入外部組件的
const {ccclass, property} = cc._decorator@ccclass
export default class Helloworld extends cc.Component {@property(cc.Label)label!: cc.LabelonLoad(): void {// 通過cc.EMP獲取Component模塊// 再通過Component模塊拓展出漸變背景色組件const {colorGrad} = cc.EMP.Components// 獲取labelNode 節點const labelNode = cc.find('labelNode', this.node)const label = cc.find('label', labelNode)// 通過addComponent添加漸變背景色,并設置腳本屬性 _colorslabelNode.addComponent(colorGrad)._colors = [cc.Color.WHITE.fromHEX('#ffffff'),cc.Color.WHITE.fromHEX('#5A51FF'),cc.Color.WHITE.fromHEX('#8668FF'),cc.Color.WHITE.fromHEX('#5A51FF'),]setTimeout(() => {// 重設labelNode節點寬高labelNode.setContentSize(label.width, label.height)})}
}
五. 已有項目如何接入
接入步驟如下:
- 在根項目安裝
emp
相關依賴;
yarn add -D @efox/cli
yarn add -D @efox/emp-tsconfig
yarn add -D @efox/emp-cocos2d
- 在
package.json
添加如下片段:
{...,"scripts": {...,+ "dev": "emp dev",+ "build": "emp build --ts --env prod && cp -r ./dist/. ./build/web-mobile"}
}
- 根目錄創建
emp-config.js
,并復制以下內容
const withCocos2d = require('@efox/emp-cocos2d')
const ip = require('ip')module.exports = withCocos2d(({config, env, empEnv}) => {const port = 9000const projectName = 'empCocos2dDemo'const host = ip.address()const publicPath = `http://${host}:${port}/`config.plugin('mf').tap(args => {args[0] = {...args[0],...{name: projectName,library: {type: 'var', name: projectName},filename: 'emp.js',// remotes: {// },exposes: {},},}return args})config.output.publicPath(publicPath)config.devServer.host(host)config.devServer.port(port)},{// creator開啟的服務端口creatorPort: 7456,// 引用基站資源鏈接empJs: [],},
)
- 將
tsconfig.json
替換如下內容:
{"extends": "@efox/emp-tsconfig","compilerOptions": {"experimentalDecorators": true,"baseUrl": "./"},"include": ["src", "creator.d.ts", "index.d.ts", "assets"]
}
- 創建
src
目錄,并新建index.ts
export type EMPData = {}const EMP: EMPData = {}if (window.boot) {const fn = window.bootwindow.boot = async function () {cc.EMP = EMPfn()}
} else {cc.EMP = EMP
}
- 創建
index.d.ts
,定義cc.EMP
類型聲明
import {EMPData} from './src'declare global {namespace cc {export let EMP: EMPData}interface Window {boot: () => void}
}
六. 總結
目前 creator cocos
游戲開發只能依賴官方開發工具,接入這套模型,能使得項目定制化更加便捷,且具有以下優點:
- 幾乎零成本接入
首先看看接入 emp
后的 creator cocos項目目錄結構

由上圖可以看出,與 普通的creator cocos2項目 相比,只多了以下2個文件和1個目錄;
- src/*
- emp-config.js
- index.d.ts
無需改變原游戲代碼任何的部分,做到了幾乎0成本接入
- 將開發方式回歸到我們熟悉的步伐上,且更靈活,原本的開發方式是GUI工具制作 一個一個
prefab
,再寫一個一個腳本綁定進去,雖然操作簡單,但開發體驗很不好,接入模型后,GUI工具依然負責制作prefab
,但腳本就可以抽離出來由webpack構建,這能給編寫的腳本帶來更多的新特性,豐富開發方式; - 組件開發靈活,多項目共享,當前開發游戲組件只能在當前項目復用,如果其他游戲項目也想用呢?這時可能會想到發布到官方托管的倉庫或者npm倉庫,但是有個問題,如果這個組件依賴了圖片,那發布到npm倉庫可能是一個難題;
emp基站
的模型能很好地解決這些問題,因為本身游戲項目就是一個基站,其他游戲項目可以輕松復用其他游戲expose
出來的組件
不同游戲項目之間組件的互相調用,可以參考 EMP中的cocos2d
基于Webpack 5 Module Federation實現的 EMP微前端方案,creator cocos這種閉源的開發過程都能接入 EMP
,證明這套方案并不局限技術棧;如果是剛開始接觸微前端的話,可以嘗試去了解一下,可以帶給你很好的使用體驗喔
具體的EMP微前端方案教程目錄如下:
- 基礎知識解析
什么是微前端
對比多種微前端方案
webpack5 module Federation原理學習
EMP的設計架構 - 快速入門
react項目如何使用和接入EMP
vue項目如何使用和接入EMP
輔助插件的使用教程 - 進階教程
Vue和React項目如何互相遠程調用
cocos2d 項目如何使用和接入EMP
教你基站搭建技巧