基於H5 canvas API 編寫的掃雷遊戲第二部分:方塊類和工具物件

JSER發表於2018-11-11

樣式表檔案

不好意思上篇沒有貼樣式表,先補充上來 /assets/css/style.css

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

body {
  background-color: #fbe9e7;
}

.game-wrapper {
  width: 100%;
  max-width: 480px;
  margin: auto;
  padding: 0 6px 6px;
}

.game-wrapper canvas.game-ui {
  display: block;
  width: 100%;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
複製程式碼

方塊類

掃雷遊戲介面由很多方塊租成,方塊應該有自己的座標(行和列),還有它周圍的雷數量,是否被標記(插上紅旗),是否已被點開;方塊應該有描述如何繪製自己的方法;這包括文字,圖示,背景的繪製;最後我們會建立一個通用的繪製方法,實現方塊的繪製功能;

class Block {
  constructor({ row, col, num = 0 }) {
    this.row = row
    this.col = col
    this.num = num
    this.isFlag = false
    this.isOpened = false
  }

  // 繪製文字 雷數量
  drawText({ context, size, space }) {
    let fontSize = size / 2 + 'px'
    let color = ({ 1: '#ff0', 2: '#0f0' })[this.num] || '#f00'
    let fw = context.measureText(this.num).width
    let tx = this.col * size + (size - space - fw) / 2
    let ty = this.row * size + (size - space - fw) / 2
    context.save()
    context.font = `bold ${fontSize} serif`
    context.textBaseline = 'hanging'
    context.fillStyle = color
    context.fillText(this.num, tx, ty)
    context.restore()
  }
  
  // 繪製圖示 雷和旗幟
  drawIcon({ context, size, space, icon }) {
    let dw, dh
    if (icon.width > icon.height) {
      dw = size * .5
      dh = dw * (icon.height / icon.width)
    } else {
      dh = size * .5
      dw = dh * (icon.width / icon.height)
    }
    let dx = this.col * size + space + (size - space - dw) / 2
    let dy = this.row * size + space + (size - space - dh) / 2
    context.drawImage(icon, dx, dy, dw, dh)
  }
  
  // 繪製背景
  drawBG({ context, size, space, icon }) {
    context.drawImage(
      icon, 0, 0, icon.width, icon.height,
      this.col * size + space, this.row * size + space, size - space, size - space
    )
  }
  // 通用的繪製方法
  draw({ context, size, space = 6 }) {
    let params = { context, size, space }
    let { blockEnd, bomb, blockFront, flag } = source.icons
    if (this.isOpened) {
      this.drawBG({ ...params, icon: blockEnd })
      if (this.num > 0 && this.num < 9) {
        this.drawText(params)
      } else if (this.num === 9) {
        this.drawIcon({ ...params, icon: bomb })
      }
    } else {
      this.drawBG({ ...params, icon: blockFront })
      if (this.isFlag) {
        this.drawIcon({ ...params, icon: flag })
      }
    }
  }
}
複製程式碼

工具物件

把一些方法放到工具物件中,是為了減輕遊戲類的重量

const utils = {
  // 建立一個畫布包裹容器
  createWrapper(mountEl) {
    mountEl = mountEl || document.body
    const wrapper = document.createElement('div')
    wrapper.className = 'game-wrapper'
    mountEl.appendChild(wrapper)
    return wrapper
  },
  // 建立畫布
  createCanvas(wrapper) {
    const canvas = document.createElement('canvas')
    canvas.className = 'game-ui'
    wrapper.appendChild(canvas)
    return canvas
  },
  // 獲取裝置畫素比 基於畫素比的尺寸是為了讓畫布適應高分屏
  getPixRatio(context) {
    var backingStore = context.backingStorePixelRatio ||
      context.webkitBackingStorePixelRatio ||
      context.mozBackingStorePixelRatio || 1
    return (window.devicePixelRatio || 1) / backingStore
  },
  
  // 生成初始方塊陣列
  genBlocks(rows, cols) {
    const blocks = []
    for (let row = 0; row < rows; row++) {
      for (let col = 0; col < cols; col++) {
        blocks.push(new Block({ row, col }))
      }
    }
    return blocks
  },

  // 判斷是否是函式
  isFunc(func) {
    return typeof func === 'function'
  }
}
複製程式碼

今天的原始碼分享到此結束,明天我將分享遊戲的核心部分,遊戲類和遊戲控制類;大家有什麼不明白的地方可以評論區提問,謝謝觀看;前端小白,初次寫文章,寫的不好還請見諒;

相關文章