WeChat mini game is a JavaScript running environment different from the browser, without BOM and DOM API. However, pixi.js uses JavaScript combined with other HTML5 technologies to display media, create animations or manage interactive images. It relies on the BOM and DOM API provided by the browser. Therefore, if you want to use pixi.js in WeChat mini games, you need to modify the engine.
However, the mini game provides support for most Canvas 2d and WebGL 1.0 features. For support information, see RenderingContext. pixi.js can automatically detect whether WebGL or Canvas is used to create graphics.
No matter what kind of engine it is, most of what is ultimately done when the game is running is updating the screen and playing sounds with user interaction. The development language of mini games is JavaScript, so at the bottom level of the engine, the drawing API and audio API need to be called through JavaScript.
The API that a piece of JavaScript code can call during runtime depends on the host environment
. Our most commonly used console.log
is not even part of the core of the JavaScript language, but is provided by the browser hosting environment. Common hosting environments include browsers, Node.js, etc. Browsers have BOM and DOM APIs, but Node.js does not; Node.js has file and network APIs provided by Node.js core modules such as fs and net, but browsers do not have these modules. For example, the following code that runs normally in the browser will report an error when run in Node.js.
let canvas = document.createElement('canvas')复制代码
Because the Node.js host environment does not provide the built-in global variable document at all.
ReferenceError: document is not defined复制代码
The running environment of the mini game is a host environment different from the browser. It does not provide BOM and DOM API, but wx API. Through the wx API, developers can call the drawing, audio and video, network, file and other capabilities provided by Native.
If you want to create a canvas, you need to call wx.createCanvas()
let canvas = wx.createCanvas()let context = canvas.getContext('2d')复制代码
If you want to create an audio object, you need to call wx.createInnerAudioContext()
let audio = wx.createInnerAudioContext()// src 地址仅作演示,并不真实存在audio.src = 'bgm.mp3'audio.play()复制代码
If you want to get the width and height of the screen, you need to call wx.getSystemInfoSync()
let { screenWidth, screenHeight } = wx.getSystemInfoSync()复制代码
But the rendering engine based on pixi.js will create the stage and mount it in the following way When you go to page
document.body.appendChild(app.view);复制代码
, an error will occur. The reason is as mentioned above. The host environment of the mini game does not provide document and window, two global variables built into the browser. Because the mini game environment is a hosting environment different from the browser.
ReferenceError: document is not definedReferenceError: window is not defined复制代码
Therefore, basically small games developed based on pixi.js cannot be directly migrated to small games for use, because the implementation of pixi.js may more or less use browsers such as BOM and DOM. Environment-specific APIs. Only by transforming pixi.js and changing the BOM and DOM API calls to wx API calls can it run in the mini-game environment.
But we cannot change the code of pixi.js, and there is no way to directly modify the API implementation. There is another adaptation method, which is to add a layer of simulated BOM and DOM between the rendering engine and the game logic code. The adaptation layer of the API is called Adapter. This adaptation layer globally simulates the properties and methods of the window and document objects that the engine will access through the wx API, so that the engine cannot feel the differences in the environment.
Adapter is user code and is not part of the base library. For an introduction to Adapter, see the tutorial Adapter.
The running environment of the mini game is JavaScriptCore on iOS and V8 on Android, both of which have no BOM and DOM. The running environment does not have global document and window objects. Therefore, when you want to use the DOM API to create elements such as Canvas and Image, an error will occur.
const canvas = document.createElement('canvas')复制代码
But we can use wx.createCanvas and wx.createImage to encapsulate a document.
const document = { createElement: function (tagName) { tagName = tagName.toLowerCase() if (tagName === 'canvas') { return wx.createCanvas() } else if (tagName === 'image') { return wx.createImage() } } }复制代码
At this point the code can create Canvas and Image just like creating elements in the browser.
const canvas = document.createElement('canvas')const image = document.createImage('image')复制代码
Similarly, if you want to create an Image object using new Image(), just add the following code.
function Image () { return wx.createImage() }复制代码
这些使用 wx API 模拟 BOM 和 DOM 的代码组成的库称之为 Adapter。顾名思义,这是对基于浏览器环境的游戏引擎在小游戏运行环境下的一层适配层,使游戏引擎在调用 DOM API 和访问 DOM 属性时不会产生错误。
Adapter 是一个抽象的代码层,并不特指某一个适配小游戏的第三方库,每位开发者都可以根据自己的项目需要实现相应的 Adapter。官方实现了一个 Adapter 名为 weapp-adapter, 并提供了完整的源码,供开发者使用和参考。
**
Adapter 下载地址 weapp-adapter.zip
weapp-adapter 会预先调用 wx.createCanvas() 创建一个上屏 Canvas,并暴露为一个全局变量 canvas。
require('./weapp-adapter')var context = canvas.getContext('2d') context.fillStyle = 'red'context.fillRect(0, 0, 100, 100)复制代码
除此之外 weapp-adapter 还模拟了以下对象和方法:
需要强调的是,weapp-adapter 对浏览器环境的模拟是远不完整的,仅仅只针对游戏引擎可能访问的属性和调用的方法进行了模拟,也不保证所有游戏引擎都能通过 weapp-adapter 顺利无缝接入小游戏。直接将 weapp-adapter 提供给开发者,更多地是作为参考,开发者可以根据需要在 weapp-adapter 的基础上进行扩展,以适配自己项目使用的游戏引擎。
小游戏基础库只提供 wx.createCanvas 和 wx.createImage 等 wx API 以及 setTimeout/setInterval/requestAnimationFrame 等常用的 JS 方法。
window对象是浏览器环境下的全局对象。小游戏运行环境中没有BOM API,因此没有window对象。但是小游戏提供了全局对象GameGlobal,所有全局定义的变量都是GameGlobal的属性。
console.log(GameGlobal.setTimeout === setTimeout);console.log(GameGlobal.requestAnimationFrame === requestAnimationFrame);复制代码
以上代码执行结果均为true。 开发者可以根据需要把自己封装的类和函数挂载到GameGlobal上。
GameGlobal.render = function(){ // 具体的方法实现} render();复制代码
import { canvas } from './canvas'/** * Base Element */export class Element { style = { cursor: null } appendChild() {} removeChild() {} addEventListener() {} removeEventListener() {} }export const HTMLCanvasElement = canvas.constructorexport const HTMLImageElement = wx.createImage().constructorexport class HTMLVideoElement extends Element { }复制代码
import { Canvas } from './canvas'import Image from './Image'import { Element } from './element'const stack = {}/** * document 适配 */export default { body: new Element('body'), addEventListener(type, handle) { stack[type] = stack[type] || [] stack[type].push(handle) }, removeEventListener(type, handle) { if (stack[type] && stack[type].length) { const i = stack[type].indexOf(handle) i !== -1 && stack[type].splice(i) } }, dispatch(ev) { const queue = stack[ev.type] queue && queue.forEach(handle => handle(ev)) }, createElement(tag) { switch (tag) { case 'canvas': { return new Canvas() } case 'img': { return new Image() } default: { return new Element() } } } }复制代码
import { noop } from './util'import Image from './Image'import { canvas } from './canvas'import location from './location'import document from './document'import WebSocket from './WebSocket'import navigator from './navigator'import TouchEvent from './TouchEvent'import XMLDocument from './XMLDocument'import localStorage from './localStorage'import XMLHttpRequest from './XMLHttpRequest'import { Element, HTMLCanvasElement, HTMLImageElement, HTMLVideoElement } from './element'const { platform } = wx.getSystemInfoSync() GameGlobal.canvas = canvas // 全局canvascanvas.addEventListener = document.addEventListener canvas.removeEventListener = document.removeEventListener// 模拟器 挂载window上不能修改if (platform === 'devtools') { Object.defineProperties(window, { Image: {value: Image}, Element: {value: Element}, ontouchstart: {value: noop}, WebSocket: {value: WebSocket}, addEventListener: {value: noop}, TouchEvent: {value: TouchEvent}, XMLDocument: {value: XMLDocument}, localStorage: {value: localStorage}, XMLHttpRequest: {value: XMLHttpRequest}, HTMLVideoElement: {value: HTMLVideoElement}, HTMLImageElement: {value: HTMLImageElement}, HTMLCanvasElement: {value: HTMLCanvasElement}, }) // 挂载 document for (const key in document) { const desc = Object.getOwnPropertyDescriptor(window.document, key) if (!desc || desc.configurable) { Object.defineProperty(window.document, key, {value: document[key]}) } } } else { GameGlobal.Image = Image GameGlobal.window = GameGlobal GameGlobal.ontouchstart = noop GameGlobal.document = document GameGlobal.location = location GameGlobal.WebSocket = WebSocket GameGlobal.navigator = navigator GameGlobal.TouchEvent = TouchEvent GameGlobal.addEventListener = noop GameGlobal.XMLDocument = XMLDocument GameGlobal.removeEventListener = noop GameGlobal.localStorage = localStorage GameGlobal.XMLHttpRequest = XMLHttpRequest GameGlobal.HTMLImageElement = HTMLImageElement GameGlobal.HTMLVideoElement = HTMLVideoElement GameGlobal.HTMLCanvasElement = HTMLCanvasElement GameGlobal.WebGLRenderingContext = GameGlobal.WebGLRenderingContext || {} }复制代码
思路建议为先引入通用的 Adapter 尝试运行,然后遇到的问题再逐个解决掉。
相关免费学习推荐:微信小程序开发
The above is the detailed content of Learn how to develop WeChat games with pixi.js. For more information, please follow other related articles on the PHP Chinese website!