天天看點

微信小遊戲學習

1月份的時候微信更新了小遊戲的功能,微信公衆平台也放出了小遊戲的開發文檔,這裡總結一下最近對小遊戲的學習。

登入微信公衆平台,能發現小程式的開發文檔下多了一個小遊戲類别。按照文檔的指引,在開發工具中建立項目時勾選“建立遊戲快速啟動模闆”就可以得到一個可以運作的小遊戲了。

微信小遊戲學習

上圖可以看到一個飛機的遊戲,在開發工具中預覽遊戲,可以進行試玩。接下來就學習一下這個飛機遊戲的代碼。

項目的完整目錄結構
|
|---audio
|  |...                     // 音頻檔案
|---images
|  |...                     // 圖檔/動畫資源
|---js
|  |---base
|  |  |---animation.js      // Sprite的子類,實作了動畫相關的功能
|  |  |---pool.js           // 一個簡單的對象池實作,減少對象建立開銷和頻繁的垃圾回收
|  |  |---sprite.js         // 遊戲基礎的精靈類
|  |---libs
|  |  |---symbol.js         // 對于ES6中Symbol的極簡相容,友善模拟私有變量
|  |  |---weapp-adapter.js  // 模拟BOM和DOM的代碼庫,使遊戲引擎在調用DOM API和通路DOM屬性時不産生錯誤
|  |---npc
|  |  |---enemy.js
|  |---player
|  |  |---bullet.js
|  |  |---index.js
|  |---runtime
|  |  |---background.js
|  |  |---gameinfo.js
|  |  |--music.js
|  |---databus.js           // 全局狀态管理器
|  |---main.js              // 遊戲主函數
|---README.md
|---game.js                 // [必要]小遊戲的入口檔案
|---game.json               // [必要]配置檔案
|---project.config.json     // 項目相關的配置檔案
           

可以看到雖然隻是一個模闆,但包含的檔案很多。不過檔案雖多,結構還是很清晰的。首先從入口檔案game.js開始。

game.js

import './js/libs/weapp-adapter'
import './js/libs/symbol'

import Main from './js/main'

new Main()
           

執行的代碼隻有一行:new Main()。接着來到main.js。順着Main類中的constructor,來到restart()中:

restart() {
    databus.reset()

    canvas.removeEventListener(
      'touchstart',
      this.touchHandler
    )

    this.bg = new BackGround(ctx)
    this.player = new Player(ctx)
    this.gameinfo = new GameInfo()
    this.music = new Music()

    this.bindLoop = this.loop.bind(this)
    this.hasEventBind = false

    // 清除上一局的動畫
    window.cancelAnimationFrame(this.aniId);

    this.aniId = window.requestAnimationFrame(
      this.bindLoop,
      canvas
    )
  }
           

這個函數中做了一些初始化工作,移除了重開遊戲對話框的Listener,然後是最重要的一步:

this.aniId = window.requestAnimationFrame(
      this.bindLoop,
      canvas
    )
           

window.requestAnimationFrame是adapter封裝的接口,内部是微信提供的接口[requestAnimationFrame()](“https://mp.weixin.qq.com/debug/wxagame/dev/document/render/frame/requestAnimationFrame.html“)。參數中的bindLoop就是main中的loop函數,在loop中同樣調用了window.requestAnimationFrame,進而使得每一幀都會調用一次loop(),進而實作了遊戲的幀循環。

接下來就到了loop()中了。

loop() {
    databus.frame++

    this.update()
    this.render()

    this.aniId = window.requestAnimationFrame(
      this.bindLoop,
      canvas
    )
  }
           

databus.frame記錄了遊戲開始到現在的幀數,在生成敵人和計算開炮時機的時候會用到。update中計算玩家和敵人的移動、碰撞等,render負責在畫布上繪制需要展示的元素。這些都和主流的遊戲結構類似。

最後來看看Sprite和Animation兩個類。

Sprite類比較簡單,其中儲存了圖檔路徑、大小、位置以及是否可見等資訊,并實作了繪制到畫布(drawToCanvas)的方法和一個簡單的碰撞檢測(isCollideWith)。碰撞檢測檢查的是一個精靈的中心點是否位于本精靈的矩形内。

Animation要稍微複雜一點,它繼承了Sprite類,實作了播放幀動畫的功能。由于隻是個簡單的實作,是以隻支援了一個幀動畫,當然簡單修改之後就可以支援多個幀動畫,更能滿足實際應用的需求。從代碼中可以看出幀動畫是通過将精靈本體設定為不可見,再通過一個定時器(setInterval)按照一個固定的速率(this.interval)依次切換幀動畫序列中的幀圖檔,主循環進行渲染時會把該圖檔顯示到畫布,達到動畫的效果。這裡比較重要的是setInterval方法,它是微信提供的一個定時器api,作用是設定一個定時器,按照指定的周期來執行注冊的回調函數。這裡的回調函數的工作就是切換幀圖檔的index。當動畫播放結束時,要結束這個定時器,這時就需要使用微信提供的clearInterval接口了。

這裡簡單總結了一下微信開發者工具中提供的小遊戲模闆,可以看到整個遊戲的生命周期都是由自己編寫代碼實作的,不像在一些引擎中隻用“填空”即可。有點奇怪的是動畫類是自己實作的,實際在寫代碼時,會發現提示中是有wx.createAnimation接口的,但文檔中并沒有給出來,可能以後會開放吧。

期待微信開發工具更新更多功能,并早日開放個人開發者釋出微信小遊戲的權限。

繼續閱讀