微信小遊戲 demo 飛機大戰 代碼分析(四)(enemy.js, bullet.js, index.js)

微信小遊戲 demo 飛機大戰 代碼分析(四)(enemy.js, bullet.js, index.js)

微信小遊戲 demo 飛機大戰 代碼分析(一)(main.js)html

微信小遊戲 demo 飛機大戰 代碼分析(二)(databus.js)canvas

微信小遊戲 demo 飛機大戰 代碼分析(三)(spirit.js, animation.js)數組

本博客將使用逐行代碼分析的方式講解該demo,本文適用於對其餘高級語言熟悉,對js還未深刻了解的同窗,博主會盡量將全部遇到的不明白的部分標註清楚,如有不正確或不清楚的地方,歡迎在評論中指正瀏覽器

本文的代碼均由微信小遊戲自動生成的demo飛機大戰中獲取微信

enemy.js

用於實現敵人對象dom

代碼函數

import Animation from '../base/animation'
import DataBus   from '../databus'

const ENEMY_IMG_SRC = 'images/enemy.png'
const ENEMY_WIDTH   = 60
const ENEMY_HEIGHT  = 60

const __ = {
  speed: Symbol('speed')
}

let databus = new DataBus()

function rnd(start, end){
  return Math.floor(Math.random() * (end - start) + start)
}

export default class Enemy extends Animation {
  constructor() {
    super(ENEMY_IMG_SRC, ENEMY_WIDTH, ENEMY_HEIGHT)

    this.initExplosionAnimation()
  }

  init(speed) {
    this.x = rnd(0, window.innerWidth - ENEMY_WIDTH)
    this.y = -this.height

    this[__.speed] = speed

    this.visible = true
  }

  // 預約義爆炸的幀動畫
  initExplosionAnimation() {
    let frames = []

    const EXPLO_IMG_PREFIX  = 'images/explosion'
    const EXPLO_FRAME_COUNT = 19

    for ( let i = 0;i < EXPLO_FRAME_COUNT;i++ ) {
      frames.push(EXPLO_IMG_PREFIX + (i + 1) + '.png')
    }

    this.initFrames(frames)
  }

  // 每一幀更新子彈位置
  update() {
    this.y += this[__.speed]

    // 對象回收
    if ( this.y > window.innerHeight + this.height )
      databus.removeEnemey(this)
  }
}

初始化

導入相應文件

建立所需常量

分別是敵機的圖片位置,高度和寬度動畫

建立symbol常量和databus對象

rnd(start,end)

  • Math.random() 用於提供[0,1)區間的浮點數
  • Math.floor() 返回小於等於該數字最大的整數
  • 該函數的做用是返回一個start到end區間(end不取)返回內的一個隨機數
  • 在後面該函數用於生成敵機的位置

Enemy

敵人類,繼承與Animation類this

constructor()

構造器code

  • 根據提供的常量初始化敵機對象
  • 而且初始化爆炸動畫,該函數在以後實現

init(speed)

初始化敵機速度

  • 獲取隨機生成x座標做爲起始x位置
  • 獲取其自己的高度取負值做爲起始y座標(一開始整個敵機還未進入屏幕,慢慢一點一點進入)
  • js中座標原點爲屏幕左上角,以原點向左爲x正方向,原點向下爲y正方向,

initExplosionAnimation()

定義爆炸幀動畫

  • 建立一個數組
  • 設定爆炸的每一幀動畫的具體位置,以及數量
  • 建立一個frames數組,將圖片按順序讀取並加入數組中
  • 將該數組做爲Animation類中定義的方法initFrames的參數初始化爆炸動畫

update()

邏輯更新函數,更新物體的參數,基本每一個具體物體都具備該函數

  • 按速度沒回合加上必定的y座標(因爲敵機是往下走的,所以加上)

  • 若發現對象移動出屏幕,則將其回收

bullet.js

子彈的實現

初始化

導入相應包

定義須要的基本常量

定義symbol和生成databus

Bullet

子彈實現類,繼承於精靈類(沒有繼承於動畫類,其無需動畫)

代碼

import Sprite   from '../base/sprite'
import DataBus  from '../databus'

const BULLET_IMG_SRC = 'images/bullet.png'
const BULLET_WIDTH   = 16
const BULLET_HEIGHT  = 30

const __ = {
  speed: Symbol('speed')
}

let databus = new DataBus()

export default class Bullet extends Sprite {
  constructor() {
    super(BULLET_IMG_SRC, BULLET_WIDTH, BULLET_HEIGHT)
  }

  init(x, y, speed) {
    this.x = x
    this.y = y

    this[__.speed] = speed

    this.visible = true
  }

  // 每一幀更新子彈位置
  update() {
    this.y -= this[__.speed]

    // 超出屏幕外回收自身
    if ( this.y < -this.height )
      databus.removeBullets(this)
  }
}

constructor

構造器

  • 經過預設置的常量初始化超類

init(x, y, speed)

初始化座標位置和速度

update()

邏輯更新函數

  • 爲y座標向上增長速度的大小,即應該減去速度的數值
  • 將整個子彈超出屏幕外的(所以是小於-this.height而不是0)移入對象池中,即出遊戲

index.js

玩家類

代碼

import Sprite   from '../base/sprite'
import Bullet   from './bullet'
import DataBus  from '../databus'

const screenWidth    = window.innerWidth
const screenHeight   = window.innerHeight

// 玩家相關常量設置
const PLAYER_IMG_SRC = 'images/hero.png'
const PLAYER_WIDTH   = 80
const PLAYER_HEIGHT  = 80

let databus = new DataBus()

export default class Player extends Sprite {
  constructor() {
    super(PLAYER_IMG_SRC, PLAYER_WIDTH, PLAYER_HEIGHT)

    // 玩家默認處於屏幕底部居中位置
    this.x = screenWidth / 2 - this.width / 2
    this.y = screenHeight - this.height - 30

    // 用於在手指移動的時候標識手指是否已經在飛機上了
    this.touched = false

    this.bullets = []

    // 初始化事件監聽
    this.initEvent()
  }

  /**
   * 當手指觸摸屏幕的時候
   * 判斷手指是否在飛機上
   * @param {Number} x: 手指的X軸座標
   * @param {Number} y: 手指的Y軸座標
   * @return {Boolean}: 用於標識手指是否在飛機上的布爾值
   */
  checkIsFingerOnAir(x, y) {
    const deviation = 30

    return !!(   x >= this.x - deviation
              && y >= this.y - deviation
              && x <= this.x + this.width + deviation
              && y <= this.y + this.height + deviation  )
  }

  /**
   * 根據手指的位置設置飛機的位置
   * 保證手指處於飛機中間
   * 同時限定飛機的活動範圍限制在屏幕中
   */
  setAirPosAcrossFingerPosZ(x, y) {
    let disX = x - this.width / 2
    let disY = y - this.height / 2

    if ( disX < 0 )
      disX = 0

    else if ( disX > screenWidth - this.width )
      disX = screenWidth - this.width

    if ( disY <= 0 )
      disY = 0

    else if ( disY > screenHeight - this.height )
      disY = screenHeight - this.height

    this.x = disX
    this.y = disY
  }

  /**
   * 玩家響應手指的觸摸事件
   * 改變戰機的位置
   */
  initEvent() {
    canvas.addEventListener('touchstart', ((e) => {
      e.preventDefault()

      let x = e.touches[0].clientX
      let y = e.touches[0].clientY

      //
      if ( this.checkIsFingerOnAir(x, y) ) {
        this.touched = true

        this.setAirPosAcrossFingerPosZ(x, y)
      }

    }).bind(this))

    canvas.addEventListener('touchmove', ((e) => {
      e.preventDefault()

      let x = e.touches[0].clientX
      let y = e.touches[0].clientY

      if ( this.touched )
        this.setAirPosAcrossFingerPosZ(x, y)

    }).bind(this))

    canvas.addEventListener('touchend', ((e) => {
      e.preventDefault()

      this.touched = false
    }).bind(this))
  }

  /**
   * 玩家射擊操做
   * 射擊時機由外部決定
   */
  shoot() {
    let bullet = databus.pool.getItemByClass('bullet', Bullet)

    bullet.init(
      this.x + this.width / 2 - bullet.width / 2,
      this.y - 10,
      10
    )

    databus.bullets.push(bullet)
  }
}

初始化

導入相應文件

獲取屏幕大小做爲常量

建立基本常量

Player

玩家類,繼承於Spirit類

構造器

  • 初始化超類
  • 設置玩家初始位置,位於屏幕底部而且居中(應注意判斷位置是判斷其左上角位置)
  • 設定判斷是否有觸碰的變量和子彈數組
  • 初始化事件監聽函數
    • 事件監聽至關因而在等待事件的發生,一旦發生就會隨之執行的函數

checkIsFingerOnAir(x, y)

判斷玩家手指是否在飛機上

  • deviation變量至關因而擴展玩家手指對飛機控制的範圍設定的參數
  • 判斷手指與飛機的關係和位置

setAirPosAcrossFingerPosZ(x, y)

根據手指的位置設置飛機的位置

保證手指處於飛機中間

同時限定飛機的活動範圍限制在屏幕中

initEvent()

監聽函數

  • 綁定touchstart事件, 即開始觸碰事件,並傳入一個匿名函數做爲回調函數,做爲觸發該事件時的回調
    • 若觸碰時觸碰的是飛機則將飛機被觸碰設置爲真而且將飛機中心移動到手指中心
    • e.preventDefault() 這是取消事件自己的默認動做的函數
  • 綁定touchmove事件,即觸碰移動
    • 若觸碰飛機狀況爲真,則將飛機移動到相應位置
  • 綁定touchend事件,即觸碰結束

shoot()

玩家射擊函數

  • 從對象池中取一個子彈
  • 根據玩家位置初始化子彈位置
相關文章
相關標籤/搜索