目前,Cocos、Laya 已经完成了自身引擎及其工具对淘宝小游戏的适配和支持,对应的官方文档已经对接入淘宝小游戏开发做了介绍。
引擎 |
版本 |
Cocos |
3.x版本:https://docs.cocos.com/creator/manual/zh/editor/publish/publish-taobao-mini-game.html 2.x版本:https://docs.cocos.com/creator/2.4/manual/zh/publish/publish-taobao-mini-game.html 注意:Cocos最低支持版本是2.4.12,低于2.4.12版本不支持。 |
LayaBox |
LayaAir3.x在3.1.1及后续版本支持淘宝小游戏,下载使用地址:https://layaair.layabox.com/#/engineDownload LayaAir2.x在2.13.4及后续版本支持淘宝小游戏,下载使用地址:https://ldc2.layabox.com/layadownload/?type=layaairide-LayaAir%20IDE%202.13.4 |
一段 JavaScript 代码在运行时可以调用的 API 是依赖于 宿主环境 的。我们最常用的console.log
甚至都不是 JavaScript 语言核心的一部分,而是浏览器这个宿主环境提供的。常见的宿主环境有浏览器、Node.js 等。浏览器有 BOM 和 DOM API,而 Node.js 则没有;Node.js 有 fs、net 等 Node.js 核心模块提供的文件、网络 API,而浏览器则不具备这些模块。
小游戏的运行环境是一个不同于浏览器的宿主环境,没有提供 BOM 和 DOM API,提供的是 my API,开发者可以调用 Native 提供的绘制、音视频、网络、文件等能力。
如果你想创建画布,你需要调用 my.createCanvas()
let canvas = my.createCanvas() let context = canvas.getContext('2d')
如果你想创建一个音频对象,你需要调用 my.createInnerAudioContext()
let audio = my.createInnerAudioContext() // src 地址仅作演示,并不真实存在 audio.src = 'bgm.mp3' audio.play()
但是基于 HTML5 的游戏引擎会通过以下方式去创建画布、音频,获取屏幕宽高
let canvas = document.createElement('canvas') let audio = document.createElement('audio') console.log(window.innerWidth) console.log(window.innerHeight)
此时会产生错误,理由如前文所述,小游戏这个宿主环境根本没有提供 document 和 window 这两个在浏览器中内置的全局变量。因为小游戏环境是一个不同于浏览器的宿主环境。
ReferenceError: document is not defined ReferenceError: window is not defined
所以,基本上所有基于 HTML5 的游戏引擎都不能直接迁移到小游戏中使用,因为引擎可能或多或少都用到了 BOM 和 DOM 这些浏览器环境特有的 API。只有对引擎进行改造,将对 BOM 和 DOM API 的调用改成 my API 的调用,引擎才能运行在小游戏环境中。
除了修改引擎,还有一种适配方式,即在引擎和游戏逻辑代码之间加一层模拟 BOM 和 DOM API 的适配层,我们称之为 Adaptor。这层适配层在全局通过 my API 模拟了引擎会访问到的那部分 window 和 document 对象的属性和方法,使引擎感受不到环境的差异。
除去Cocos与Laya,开发者如果想用其他 HTML5 游戏引擎来开发小游戏也是可以的,但需要对其进行修改。修改思路建议为先实现 Adaptor 并尝试运行,再把遇到的问题逐个解决。
淘宝小游戏中不支持全局变量的直接挂载和访问,这一点可能与其他平台有差异,需额外注意。
例如以下的写法会导致报错,该现象往往出现在跨脚本文件之间的相互访问。
// 文件A中定义函数testFn var testFn = function() { console.log("test") }
// 文件B中引入A require("A.js"); // 直接调用testFn函数会报错 testFn();
淘宝小游戏提供了统一的全局变量 $global
,开发者可手动挂载方法到$global上,即可解决问题。
具体示例如下,修改文件A:
// 文件A中定义函数testFn var testFn = function() { console.log("test") } // 手动挂载到$global上,推荐一般的业务内变量挂载到 $global.window $global.window.testFn = testFn;
文件B中通过以下方式调用函数:
// 文件B中引入A require("A.js"); // 调用函数 $global.window.testFn(); // 正确输出 -> test
使用Cocos开发时可在构建面板填写全局变量,抹平与其他平台的差异。引擎在构建发布时会帮开发者自动在各文件中注入全局变量。
如填写foo,各个脚本文件中就会在头部自动定义好变量,即可无视平台差异。实现原理具体如下:
// 自动注入在各脚本文件中,无需再手动定义 var window = $global; var foo = window.foo;
window 变量是 global 的引用,需要先确保 global上变量已经存在,定义的临时变量才会有值。若使用自定义脚本或使用第三方插件,发现全局变量不存在,通常是加载时机问题导致脚本还没被加载,就使用到了脚本内的全局变量。
Spine在小游戏上存在问题,请使用如下代码暂时修复问题:
et oldClear = sp.spine.IntSet.prototype.clear sp.spine.IntSet.prototype.clear = function() { oldClear.apply(this); this.array = []; }
① 确保是小游戏(新)类型。
② IDE的【详情】的【项目配置】打开云构建。
③ 分包文件大小不能超过4M。
④ 主场景要放在主包里面,不能放在分包里面。
临时方案处理:
\ProgramData\cocos\editors\Creator\3.8.3\resources\resources\3d\engine\pal\minigame\taobao_minigame.ts路径文件中的方法createInnerAudioContext
// eslint-disable-next-line func-names minigame.createInnerAudioContext = function (): InnerAudioContext { // NOTE: `onCanPlay` is not standard minigame interface, // so here we mark audio as type of any const audio: any = polyfilledCreateInnerAudio(); audio.onCanplay = audio.onCanPlay.bind(audio); delete audio.onCanPlay; return audio as InnerAudioContext; };
删除两行代码:
audio.onCanplay = audio.onCanPlay.bind(audio);
delete audio.onCanPlay;
CocosCreator 3.8.5修复这个问题;开发者可以参考:https://github.com/cocos/cocos-engine/pull/16958
修改脚本:cocos\editors\Creator\2.4.13\resources\engine\cocos2d\core\physics\box2d-adapter.js
如果有开启动态合图,请尝试关闭;
如果在Cocos工程中直接引入@tbmp/mp-cloud-sdk的话,初始化的方式有所改变:
import cloud from '@tbmp/mp-cloud-sdk'; let cloudObject = new cloud.Cloud(); try { cloudObject.init({ env: 'online' }); }catch (e) { console.error("cloud初始化错误:" + e); }
之后的操作需要使用cloundObject来进行。比如之前在淘宝小游戏项目中调用http接口的:
const result = await cloud.application.httpRequest({...});
在cocos中的调用是:
const result = await cloudObject.application.httpRequest({...});