微信小遊戲 demo 飛機大戰 代碼分析(二)(databus.js)html
微信小遊戲 demo 飛機大戰 代碼分析(三)(spirit.js, animation.js)canvas
微信小遊戲 demo 飛機大戰 代碼分析(四)(enemy.js, bullet.js, index.js)數組
本博客將使用逐行代碼分析的方式講解該demo,本文適用於對其餘高級語言熟悉,對js還未深刻了解的同窗,博主會盡量將全部遇到的不明白的部分標註清楚,如有不正確或不清楚的地方,歡迎在評論中指正瀏覽器
本文的代碼均由微信小遊戲自動生成的demo飛機大戰中獲取微信
首先讓咱們來看一下做爲入口的game.js,能夠看到在這裏只進行了main類的初始化,所以下一步咱們應該查看一下main類中的函數ide
代碼函數
import Player from './player/index' import Enemy from './npc/enemy' import BackGround from './runtime/background' import GameInfo from './runtime/gameinfo' import Music from './runtime/music' import DataBus from './databus' let ctx = canvas.getContext('2d') let databus = new DataBus() /** * 遊戲主函數 */ export default class Main { constructor() { // 維護當前requestAnimationFrame的id this.aniId = 0 //從新生成新的界面 this.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 ) } /** * 隨着幀數變化的敵機生成邏輯 * 幀數取模定義成生成的頻率 */ enemyGenerate() { if ( databus.frame % 30 === 0 ) { let enemy = databus.pool.getItemByClass('enemy', Enemy) enemy.init(6) databus.enemys.push(enemy) } } // 全局碰撞檢測 collisionDetection() { let that = this databus.bullets.forEach((bullet) => { for ( let i = 0, il = databus.enemys.length; i < il;i++ ) { let enemy = databus.enemys[i] if ( !enemy.isPlaying && enemy.isCollideWith(bullet) ) { enemy.playAnimation() that.music.playExplosion() bullet.visible = false databus.score += 1 break } } }) for ( let i = 0, il = databus.enemys.length; i < il;i++ ) { let enemy = databus.enemys[i] if ( this.player.isCollideWith(enemy) ) { databus.gameOver = true break } } } // 遊戲結束後的觸摸事件處理邏輯 touchEventHandler(e) { e.preventDefault() let x = e.touches[0].clientX let y = e.touches[0].clientY let area = this.gameinfo.btnArea if ( x >= area.startX && x <= area.endX && y >= area.startY && y <= area.endY ) this.restart() } /** * canvas重繪函數 * 每一幀從新繪製全部的須要展現的元素 */ render() { ctx.clearRect(0, 0, canvas.width, canvas.height) this.bg.render(ctx) databus.bullets .concat(databus.enemys) .forEach((item) => { item.drawToCanvas(ctx) }) this.player.drawToCanvas(ctx) databus.animations.forEach((ani) => { if ( ani.isPlaying ) { ani.aniRender(ctx) } }) this.gameinfo.renderGameScore(ctx, databus.score) // 遊戲結束中止幀循環 if ( databus.gameOver ) { this.gameinfo.renderGameOver(ctx, databus.score) if ( !this.hasEventBind ) { this.hasEventBind = true this.touchHandler = this.touchEventHandler.bind(this) canvas.addEventListener('touchstart', this.touchHandler) } } } // 遊戲邏輯更新主函數 update() { if ( databus.gameOver ) return; this.bg.update() databus.bullets .concat(databus.enemys) .forEach((item) => { item.update() }) this.enemyGenerate() this.collisionDetection() if ( databus.frame % 20 === 0 ) { this.player.shoot() this.music.playShoot() } } // 實現遊戲幀循環 loop() { databus.frame++ this.update() this.render() this.aniId = window.requestAnimationFrame( this.bindLoop, canvas ) } }
main 即爲遊戲的主函數,咱們來逐個分析一下其內容oop
在main函數前其調用生成了一個2d畫布,名稱爲ctx動畫
生成了一個數據總線對象databus,數據總線的內容將在下次博客中解釋this
contructor 用於建立main 對象,其中調用了restart函數,所以咱們跳轉到restart函數中進行查看
該函數用於從新生成一個界面
首先重置數據總線對象的內容
監聽觸碰事件
初始化背景對象,玩家對象,遊戲信息對象和音樂對象
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 )
js語法中,能夠將某個對象的方法單獨拿出來做爲一個方法使用,可是在使用過程當中,避免不了出現未知該函數所指向的對象的狀況
this.bindLoop = this.loop
那麼該函數所屬的類就丟失了,那麼該函數一些執行也就沒法進行window.requestAnimationFrame()
該函數用於生成敵人飛機
全局碰撞檢測
遊戲結束後判斷是否從新開始的函數
渲染函數,用於渲染場景,用於每次修改內容後從新渲染場景內容(每一幀調用)
遊戲邏輯更新主函數
實現遊戲幀循環
window.requestAnimationFrame
進行調用,爲下一幀界面渲染作準備