构建
Estella 项目可以从编辑器构建到两个目标平台:可玩广告(单个自包含 HTML 文件)和微信小游戏(可直接在微信开发者工具中打开的目录结构)。
构建目标
| 平台 | 输出 | 说明 |
|---|---|---|
| 可玩广告 | 单个 .html 文件 | 所有资源、WASM 和脚本内联到一个文件中。适用于要求单文件交付的广告平台。 |
| 微信小游戏 | 目录 | 包含 game.js、game.json、project.config.json、场景文件和资源。可直接在微信开发者工具中打开。 |
工具链配置
首次构建前,编辑器需要 C++ 工具链来编译引擎 WASM 二进制。打开构建设置,展开 Toolchain (emsdk) 部分。状态徽章显示工具链是否就绪:
| 状态 | 含义 |
|---|---|
| Ready(绿色) | Emscripten、CMake 和 Python 均已检测到且满足最低版本要求 |
| Not ready(红色) | 一个或多个工具缺失或版本过低 |
自动安装
点击 Auto Install 下载预打包的工具链(约 550–700 MB,取决于平台)。包含 Emscripten 5.0.0、CMake 和 Python,无需任何外部依赖。下载进度会在 Toast 通知中实时显示。
手动配置
如果你已经安装了 emsdk,点击 Select emsdk 并指向 emsdk 根目录。编辑器会自动校验路径并检测版本。
引擎模块
每个构建配置可以选择在 WASM 二进制中包含哪些引擎模块:
| 模块 | 说明 |
|---|---|
| Tilemap | 2D 瓦片地图渲染器 |
| Particles | 粒子系统 |
| Timeline | 时间轴动画系统 |
| PostProcess | 后处理效果 |
| Bitmap Text | 位图字体渲染 |
| Spine | Spine 骨骼动画(可选运行时版本:3.8、4.1、4.2) |
| Physics | Box2D 物理(编译为独立 WASM 模块) |
关闭不使用的模块可以减小输出 WASM 体积。引擎仅在模块配置变化时重新编译;相同配置的后续构建使用缓存结果。
使用构建面板
从编辑器工具栏打开构建面板。面板采用三栏布局:
- 左侧边栏 — 列出平台和构建配置。点击平台进行筛选,然后选择一个配置。
- 中间详情 — 显示所选配置的设置:场景列表、脚本定义和平台专属选项。
- 右侧输出 — 显示构建历史、状态、输出大小和操作按钮(打开文件夹、预览)。
创建构建配置
点击工具栏中的添加来创建新配置。选择名称和目标平台。编辑器还提供了预置的模板(通过模板按钮访问),包含”可玩广告生产版”或”微信开发版”等常用配置。
执行构建
- 从侧边栏选择一个配置
- 检查场景列表——点击添加当前场景可以将编辑器中当前打开的场景加入列表
- 根据需要调整平台专属设置
- 点击构建(或按
Cmd/Ctrl + B)
构建进度和日志通过 Toast 通知实时显示。构建完成后,可以点击打开文件夹导航到输出位置。
构建模板
点击工具栏中的模板按钮可以从预设创建配置。内置模板:
| 模板 | 平台 | 说明 |
|---|---|---|
| Facebook Playable | 可玩广告 | 针对 Facebook 2 MB 限制优化,启用代码压缩 |
| Google Playable | 可玩广告 | 针对 Google 5 MB 限制优化 |
| Playable Debug | 可玩广告 | 开发构建,带 DEBUG 定义 |
| WeChat Production | 微信小游戏 | 分包模式,竖屏方向 |
| WeChat Debug | 微信小游戏 | 单包模式,带 DEBUG 定义 |
| WeChat Single File | 微信小游戏 | 单文件打包,适合简单游戏 |
| WeChat Landscape | 微信小游戏 | 横屏方向,适合宽屏游戏 |
你还可以在详情面板中通过保存为预设将任何现有配置保存为自定义模板。
构建配置
每个配置包含:
| 设置 | 作用 |
|---|---|
| 名称 | 此配置的可读标签 |
| 平台 | 目标平台:可玩广告或微信小游戏 |
| 场景 | 要包含在构建中的 .esscene 文件列表 |
| 脚本定义 | 编译时定义(如 DEBUG)。可在脚本中通过 process.env.DEBUG 访问。 |
| 平台设置 | 平台专属选项(见下文) |
可玩广告设置
| 设置 | 描述 |
|---|---|
| 启动场景 | 启动时加载的场景(默认为列表中的第一个场景) |
| 开发构建 | 在输出中包含调试信息 |
| 代码压缩 | 压缩打包后的 JavaScript 以减小体积 |
| 嵌入字体 | 将字体文件内联到 HTML 中 |
| 输出路径 | 输出 .html 文件的写入位置(如 build/playable.html) |
| 启用内置 CTA | 显示内置的 “Install Now” 行动号召按钮 |
| CTA URL | 点击 CTA 按钮时打开的目标 URL |
微信小游戏设置
| 设置 | 描述 |
|---|---|
| AppID | 微信小游戏 AppID。测试时可使用 touristappid(无需注册应用)。 |
| 版本 | 版本字符串(如 1.0.0) |
| 屏幕方向 | 竖屏(Portrait)或 横屏(Landscape) |
| 打包模式 | 分包(推荐)、单包 或 单文件 |
| 输出目录 | 输出目录的写入位置(如 build/wechat) |
资源导出配置
构建系统通过三种模式决定包含哪些资源,可在编辑器中按文件夹配置:
| 模式 | 行为 |
|---|---|
auto(默认) | 仅包含在构建场景或预制体中被引用的资源 |
always | 无论是否被引用,始终包含该文件夹下所有资源 |
exclude | 永不包含该文件夹下的资源 |
资源导出模式存储在 .esengine/asset-export.json 中:
{ "version": "1.0", "folders": { "assets/ui": "always", "assets/debug": "exclude" }}文件夹会继承父级的模式。例如,如果 assets/sprites 设为 always,assets/sprites/enemies/ 下的所有文件也会被包含。
构建流程
点击构建后,编辑器会运行以下流水线:
1. 资源收集
构建扫描场景文件并递归收集:
Sprite、SpineRenderer等组件引用的纹理- 材质及其着色器依赖
- Spine 图集文件及其纹理页
- 位图字体文件及其字形纹理
- 嵌套预制体及其传递性资源引用
2. 图集打包
引用的图片会被打包到纹理图集页中(默认最大 2048x2048)。场景数据会被重写为使用图集坐标,运行时精灵会自动引用打包后的图集。
3. 材质编译
.esmaterial 文件被编译为 JSON,解析着色器引用并内联属性值。
4. 脚本打包
src/ 目录下的用户脚本通过 esbuild 编译打包。esengine SDK 作为外部模块处理——在可玩广告中内联,在微信小游戏中从 sdk.js 加载。
5. 资源构建变换
在写入资源之前,构建流水线会对包含需要重写引用的 JSON 资源应用构建变换。例如,预制体和动画剪辑包含的纹理路径需要被重映射为图集坐标。
变换通过 registerAssetBuildTransform() 注册在 AssetTypeEntry 上。内置变换包括:
| 资源类型 | 变换内容 |
|---|---|
prefab | 将 UUID 引用解析为构建路径,将图集打包的纹理引用重写为 uvOffset/uvScale |
anim-clip | 将帧纹理路径重写为图集页,添加 atlasFrame 元数据用于 UV 计算 |
两个平台发射器都通过 entry.buildTransform(content, artifact) 进行通用调用——无需按类型分支。要为需要构建时重写的自定义资源类型添加变换,请在编辑器插件中注册:
import { registerAssetBuildTransform } from 'esengine';
registerAssetBuildTransform('my-custom-type', (content, context) => { const artifact = context; // BuildArtifact const data = JSON.parse(content); // ... 重写资源引用 ... return JSON.stringify(data);});6. 平台输出
为目标平台生成最终产物:
- 可玩广告 — 将所有资源 base64 编码内联,组装成单个 HTML 文件
- 微信小游戏 — 写入包含
game.js、game.json、project.config.json、场景、资源和 WASM 文件的目录
输出结构
可玩广告
build/ playable.html # 单个自包含文件微信小游戏
build/wechat/ project.config.json # 微信开发者工具项目配置 game.json # 小游戏清单 game.js # 入口文件(引擎初始化 + 用户脚本) esengine.js # WASM 引擎加载器 esengine.wasm # 引擎 WASM 二进制 sdk.js # SDK 运行时 spine.js / spine.wasm # Spine 运行时(如果启用了 Spine) physics.js / physics.wasm # 物理引擎(如果启用了物理) atlas_0.png # 打包的纹理图集页 asset-manifest.json # 可寻址资源清单 scenes/ Level1.json # 导出的场景数据 assets/ ... # 未打包的资源文件可寻址清单
两个平台都会生成 asset-manifest.json,将资源 UUID 映射到运行时路径。这使运行时能够通过 UUID 或地址解析资源,并从打包的图集页中重建图集帧。
{ "version": "2.0", "groups": { "default": { "bundleMode": "together", "labels": [], "assets": { "uuid-1": { "path": "assets/sprites/player.png", "type": "texture", "size": 1024, "labels": ["character"] } } } }}构建钩子
每个配置可以定义构建前和构建后钩子来自动化自定义步骤。在配置详情面板的可折叠”构建钩子”区域添加钩子。每个钩子有一个阶段(pre 或 post)和一个类型(copy-files 或 run-command)。
复制文件
递归复制目录到另一个位置,可选按 glob 模式过滤文件。
| 字段 | 说明 |
|---|---|
| from | 源目录路径 |
| to | 目标目录路径 |
| pattern | 可选的文件名过滤(如 *.png、*.json)——仅复制匹配的文件 |
from 和 to 均支持路径变量:
| 变量 | 解析为 |
|---|---|
${projectDir} | 项目根目录的绝对路径 |
${outputPath} | 输出文件的完整路径(如 build/playable.html) |
${outputDir} | 输出文件所在目录(如 build/) |
运行命令
以项目根目录为工作目录(cwd)执行 shell 命令。
| 字段 | 说明 |
|---|---|
| command | 要运行的可执行程序(如 node、python3、bash) |
| args | 可选的字符串参数数组,原样传递给命令 |
命令接收到的信息:
- 工作目录 — 项目根目录(与编辑器的项目路径相同)
- 参数 —
args数组中的字面字符串(不做变量替换) - 标准输出/错误 — 被捕获并记录到构建控制台(标准输出截断为 200 字符)
- 退出码 — 非零退出码将导致构建失败
钩子示例
构建后将额外资源复制到微信输出目录:
{ "phase": "post", "type": "copy-files", "config": { "from": "${projectDir}/assets/extras", "to": "${outputDir}/assets/extras", "pattern": "*.png" }}构建前运行纹理压缩脚本(工作目录是项目根,所以相对路径可以直接使用):
{ "phase": "pre", "type": "run-command", "config": { "command": "node", "args": ["scripts/compress-textures.js", "--input", "assets/textures", "--quality", "80"] }}脚本通过 process.argv.slice(2) 获取参数:
const args = process.argv.slice(2);// args = ["--input", "assets/textures", "--quality", "80"]// process.cwd() = 项目根目录
const inputDir = args[args.indexOf('--input') + 1]; // "assets/textures"const quality = args[args.indexOf('--quality') + 1]; // "80"构建后将输出复制到部署目录:
{ "phase": "post", "type": "copy-files", "config": { "from": "${outputDir}", "to": "${projectDir}/deploy" }}配置 JSON 格式
构建配置存储在 editor-state.json 中。每个配置遵循以下结构:
{ "id": "playable-prod", "name": "Playable - Production", "platform": "playable", "scenes": ["assets/scenes/main.esscene"], "defines": [], "hooks": [ { "phase": "post", "type": "run-command", "config": { "command": "open", "args": ["${outputDir}"] } } ], "playableSettings": { "startupScene": "assets/scenes/main.esscene", "isDevelopment": false, "minifyCode": true, "embedFonts": true, "outputPath": "build/playable.html", "enableBuiltinCTA": false, "ctaUrl": "" }}微信配置将 playableSettings 替换为 wechatSettings:
{ "id": "wechat-prod", "name": "WeChat - Production", "platform": "wechat", "scenes": ["assets/scenes/main.esscene"], "defines": [], "hooks": [], "wechatSettings": { "appId": "wx1234567890", "version": "1.0.0", "bundleMode": "subpackage", "outputDir": "build/wechat", "orientation": "portrait" }}配置导入与导出
构建配置可以导出为 JSON 用于备份或团队共享:
- 导出 — 点击工具栏中的导出按钮,将所有配置保存为
.json文件 - 导入 — 点击导入按钮,从之前导出的文件中加载配置
通过保存为预设创建的自定义模板存储在 .esengine/build-templates/ 目录下的 JSON 文件中,可以提交到版本控制中供团队共享。
项目设置
构建行为还受项目级设置的影响:
| 设置 | 效果 |
|---|---|
| Spine 版本 | 在构建中包含 Spine 运行时 WASM 模块 |
| 启用物理 | 在构建中包含物理 WASM 模块并生成物理配置 |
| 物理重力 | 在物理配置中设置重力向量 |
| 物理时间步 | 设置固定的物理模拟时间步长 |