溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么用pixi.js開發(fā)微信小游戲

發(fā)布時(shí)間:2020-12-10 10:09:56 來源:億速云 閱讀:422 作者:小新 欄目:移動(dòng)開發(fā)

這篇文章給大家分享的是有關(guān)怎么用pixi.js開發(fā)微信小游戲的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考。一起跟隨小編過來看看吧。

1.使用PixiJS渲染引擎

微信小游戲是一個(gè)不同于瀏覽器的 JavaScript 運(yùn)行環(huán)境,沒有 BOM 和 DOM API。然而pixi.js是用 JavaScript 結(jié)合其他 HTML5 技術(shù)來顯示媒體,創(chuàng)建動(dòng)畫或管理交互式圖像。是依賴瀏覽器提供的 BOM 和 DOM API 的。所以如果要在微信小游戲中使用pixi.js,需要對(duì)引擎進(jìn)行改造。

不過小游戲提供了對(duì)大部分 Canvas 2d 和 WebGL 1.0 特性的支持,支持情況參見 RenderingContext,pixi.js它能自動(dòng)偵測(cè)使用WebGL還是Canvas來創(chuàng)建圖形。

無(wú)論是怎樣的引擎,最終在游戲運(yùn)行時(shí)所做的大部分事情都是 隨著用戶的交互更新畫面和播放聲音。小游戲的開發(fā)語(yǔ)言是 JavaScript,那么在引擎的底層就需要通過 JavaScript 調(diào)用繪制 API 和音頻 API。

一段 JavaScript 代碼在運(yùn)行時(shí)可以調(diào)用的 API 是依賴于 宿主環(huán)境 的。我們最常用的 console.log 甚至都不是 JavaScript 語(yǔ)言核心的一部分,而是瀏覽器這個(gè)宿主環(huán)境提供的。常見的宿主環(huán)境有瀏覽器、Node.js 等。瀏覽器有 BOM 和 DOM API,而 Node.js 則沒有;Node.js 有 fs、net 等 Node.js 核心模塊提供的文件、網(wǎng)絡(luò) API,而瀏覽器則不具備這些模塊。例如,下面這段在瀏覽器中可以正常運(yùn)行的代碼,在 Node.js 中運(yùn)行就會(huì)報(bào)錯(cuò)。

let canvas = document.createElement('canvas')復(fù)制代碼

因?yàn)?Node.js 這個(gè)宿主環(huán)境根本沒有提供 document 這個(gè)內(nèi)置的全局變量。

ReferenceError: document is not defined復(fù)制代碼

小游戲的運(yùn)行環(huán)境是一個(gè)不同于瀏覽器的宿主環(huán)境,沒有提供 BOM 和 DOM API,提供的是 wx API。通過 wx API,開發(fā)者可以調(diào)用 Native 提供的繪制、音視頻、網(wǎng)絡(luò)、文件等能力。
怎么用pixi.js開發(fā)微信小游戲
如果你想創(chuàng)建畫布,你需要調(diào)用 wx.createCanvas()

let canvas = wx.createCanvas()let context = canvas.getContext('2d')復(fù)制代碼

如果你想創(chuàng)建一個(gè)音頻對(duì)象,你需要調(diào)用 wx.createInnerAudioContext()

let audio = wx.createInnerAudioContext()// src 地址僅作演示,并不真實(shí)存在audio.src = 'bgm.mp3'audio.play()復(fù)制代碼

如果你想獲取屏幕的寬高,你需要調(diào)用 wx.getSystemInfoSync()

let { screenWidth, screenHeight } = wx.getSystemInfoSync()復(fù)制代碼

但是基于 pixi.js 渲染引擎會(huì)通過以下方式去創(chuàng)建stage 并掛載到頁(yè)面

document.body.appendChild(app.view);復(fù)制代碼

此時(shí)會(huì)產(chǎn)生錯(cuò)誤,理由如前文所述,小游戲這個(gè)宿主環(huán)境根本沒有提供 document 和 window 這兩個(gè)在瀏覽器中內(nèi)置的全局變量。因?yàn)樾∮螒颦h(huán)境是一個(gè)不同于瀏覽器的宿主環(huán)境。

ReferenceError: document is not definedReferenceError: window is not defined復(fù)制代碼

所以,基本上基于pixi.js開發(fā)的小游戲,都不能直接遷移到小游戲中使用,因?yàn)閜ixi.js的實(shí)現(xiàn)可能或多或少都用到了 BOM 和 DOM 這些瀏覽器環(huán)境特有的 API。只有對(duì)pixi.js進(jìn)行改造,將對(duì) BOM 和 DOM API 的調(diào)用改成 wx API 的調(diào)用,才能運(yùn)行在小游戲環(huán)境中。

但是pixi.js的代碼我們不能改變,也沒辦法直接去修改API的實(shí)現(xiàn),還有一種適配方式,即在渲染引擎和游戲邏輯代碼之間加一層模擬 BOM 和 DOM API 的適配層,我們稱之為 Adapter。這層適配層在全局通過 wx API 模擬了引擎會(huì)訪問到的那部分 window 和 document 對(duì)象的屬性和方法,使引擎感受不到環(huán)境的差異。
怎么用pixi.js開發(fā)微信小游戲
Adapter 是用戶代碼,不是基礎(chǔ)庫(kù)的一部分。關(guān)于 Adapter 的介紹,參見教程 Adapter。

2. Adapter 適配器

1. weapp-adapter

小游戲的運(yùn)行環(huán)境在 iOS 上是 JavaScriptCore,在 Android 上是 V8,都是沒有 BOM 和 DOM 的運(yùn)行環(huán)境,沒有全局的 document 和 window 對(duì)象。因此當(dāng)你希望使用 DOM API 來創(chuàng)建 Canvas 和 Image 等元素的時(shí)候,會(huì)引發(fā)錯(cuò)誤。

const canvas = document.createElement('canvas')復(fù)制代碼

但是我們可以使用 wx.createCanvas 和 wx.createImage 來封裝一個(gè) document。

const document = {    createElement: function (tagName) {
        tagName = tagName.toLowerCase()        if (tagName === 'canvas') {            return wx.createCanvas()
        }        else if (tagName === 'image') {            return wx.createImage()
        }
    }
}復(fù)制代碼

這時(shí)代碼就可以像在瀏覽器中創(chuàng)建元素一樣創(chuàng)建 Canvas 和 Image 了。

const canvas = document.createElement('canvas')const image = document.createImage('image')復(fù)制代碼

同樣,如果想實(shí)現(xiàn) new Image() 的方式創(chuàng)建 Image 對(duì)象,只須添加如下代碼。

function Image () {    return wx.createImage()
}復(fù)制代碼

這些使用 wx API 模擬 BOM 和 DOM 的代碼組成的庫(kù)稱之為 Adapter。顧名思義,這是對(duì)基于瀏覽器環(huán)境的游戲引擎在小游戲運(yùn)行環(huán)境下的一層適配層,使游戲引擎在調(diào)用 DOM API 和訪問 DOM 屬性時(shí)不會(huì)產(chǎn)生錯(cuò)誤。

Adapter 是一個(gè)抽象的代碼層,并不特指某一個(gè)適配小游戲的第三方庫(kù),每位開發(fā)者都可以根據(jù)自己的項(xiàng)目需要實(shí)現(xiàn)相應(yīng)的 Adapter。官方實(shí)現(xiàn)了一個(gè) Adapter 名為 weapp-adapter, 并提供了完整的源碼,供開發(fā)者使用和參考。
**
Adapter 下載地址 weapp-adapter.zip

weapp-adapter 會(huì)預(yù)先調(diào)用 wx.createCanvas() 創(chuàng)建一個(gè)上屏 Canvas,并暴露為一個(gè)全局變量 canvas。

require('./weapp-adapter')var context = canvas.getContext('2d')
context.fillStyle = 'red'context.fillRect(0, 0, 100, 100)復(fù)制代碼

除此之外 weapp-adapter 還模擬了以下對(duì)象和方法:

  • document.createElement
  • canvas.addEventListener
  • localStorage
  • Audio
  • Image
  • WebSocket
  • XMLHttpRequest
  • 等等...

需要強(qiáng)調(diào)的是,weapp-adapter 對(duì)瀏覽器環(huán)境的模擬是遠(yuǎn)不完整的,僅僅只針對(duì)游戲引擎可能訪問的屬性和調(diào)用的方法進(jìn)行了模擬,也不保證所有游戲引擎都能通過 weapp-adapter 順利無(wú)縫接入小游戲。直接將 weapp-adapter 提供給開發(fā)者,更多地是作為參考,開發(fā)者可以根據(jù)需要在 weapp-adapter 的基礎(chǔ)上進(jìn)行擴(kuò)展,以適配自己項(xiàng)目使用的游戲引擎。

2. pixi-adapter

小游戲基礎(chǔ)庫(kù)只提供 wx.createCanvas 和 wx.createImage 等 wx API 以及 setTimeout/setInterval/requestAnimationFrame 等常用的 JS 方法。

1.全局對(duì)象

window對(duì)象是瀏覽器環(huán)境下的全局對(duì)象。小游戲運(yùn)行環(huán)境中沒有BOM API,因此沒有window對(duì)象。但是小游戲提供了全局對(duì)象GameGlobal,所有全局定義的變量都是GameGlobal的屬性。

console.log(GameGlobal.setTimeout === setTimeout);console.log(GameGlobal.requestAnimationFrame === requestAnimationFrame);復(fù)制代碼

以上代碼執(zhí)行結(jié)果均為true。 開發(fā)者可以根據(jù)需要把自己封裝的類和函數(shù)掛載到GameGlobal上。

GameGlobal.render = function(){    // 具體的方法實(shí)現(xiàn)}
render();復(fù)制代碼
2. Element 元素構(gòu)造
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 {

}復(fù)制代碼
3. document 構(gòu)造
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()
      }
    }
  }
}復(fù)制代碼
4.統(tǒng)一入口
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 || {}
}復(fù)制代碼

思路建議為先引入通用的 Adapter 嘗試運(yùn)行,然后遇到的問題再逐個(gè)解決掉。

感謝各位的閱讀!關(guān)于怎么用pixi.js開發(fā)微信小游戲就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI