快速實現一個簡單的canvas迷宮遊戲

前言

(最近設計模式看的有點頭大,一直面對純js實在是有些枯燥-_-。因此寫一點有趣的東西調劑一下)
如今canvas已經不算新鮮了,不過因爲平常業務中並不經常使用,因此實踐並很少,今天分享一下,如何實現簡單canvas迷宮。這個例子來源於《html5祕籍》第二版,代碼有稍微作了點調整。html

因爲中間有一步使用canvas獲取圖片信息的時候,必須使用服務器環境。因此我先寫了一個樣例扔在服務器上,你們能夠先體驗一下效果(用成就感做爲驅動力哈哈哈)html5

點我體驗git

git地址github

正文

實現這個小遊戲也不難,讓咱們想一想,一個迷宮遊戲有哪些基本要素。canvas

首先固然得有個地圖,而後得有個移動的小人,這兩個咱們利用cavans來繪製;設計模式

接下來是物體移動的程序,這個程序主要包括2個方面:數組

1.讓物體跟咱們指定的指令來移動;
2.檢測物體是否碰到牆體或者出口。服務器

繪製迷宮的地圖和移動的小人

繪製地圖的主要步驟是:函數

  1. 獲取一張地圖的圖片
  2. 利用cavans繪製圖像。

迷宮地圖的生成,能夠藉助谷歌的一個迷宮在線生成器來得到。優化

繪製小人也是同樣直接找一個小人的圖片便可,不過這裏要注意的是,要找正方形的圖片,由於一會咱們須要作移動的碰撞檢測,方形比較好判斷。

接下來就要寫繪製迷宮和小人的主要函數

function drawMaze(mazeFile, startingX, startingY) {
  var imgMaze = new Image()
  imgMaze.onload = function () {
    // 畫布大小調整
    canvas.width = imgMaze.width
    canvas.height = imgMaze.height

    // 繪製笑臉
    var imgFace = document.getElementById("face")
    context.drawImage(imgMaze, 0, 0)

    x = startingX
    y = startingY
    context.drawImage(imgFace, x, y)
    context.stroke()
  }
  imgMaze.src = mazeFile
}

mazeFile是迷宮的圖片地址,startingXstartingY,是起始點的座標。在這裏圖片引入的方式用了2種,緣由是小人的圖片我不常常更換,就直接寫在頁面裏,迷宮的地圖打算作成可變的,因此在js裏引入,你想把圖片都直接用js引入也沒有問題。其餘部分比較簡單,再也不贅述。

移動函數

移動的主要原理是:
接受指定的用戶輸入(在這裏是響應方向鍵),轉換成對應的移動指令。而後週期性的檢查移動指令,繪製對應的目標位置。舉個簡單的例子:

好比每按下一次方向鍵上,就記錄下應該往上移動,而後每隔100毫秒檢查當前的移動指令,繪製應該移動的目標地點,重複這個過程。代碼也比較簡單:

// 移動函數
function processKey(e) {
  dx = 0
  dy = 0
  // 上下左右方向鍵檢測
  if (e.keyCode === 38) {
    dy = -1
  }
  if (e.keyCode === 40) {
    dy = 1
  }
  if (e.keyCode === 37) {
    dx = -1
  }
  if (e.keyCode === 39) {
    dx = 1
  }
}

// 繪製幀
function drawFrame() {
  if (dx != 0 || dy != 0) {
    // context.clearRect(x,y,canvas.width,canvas.height)
    // 繪製移動軌跡
    context.beginPath();
    context.fillStyle = "rgb(254,244,207)"
    context.rect(x, y, 15, 15)
    context.fill()
    x += dx
    y += dy
    // 碰撞檢測
    if (checkForCollision()) {
      x -= dx
      y -= dy
      dx = 0
      dy = 0
    }
    
    //繪製小人應該移動的地點
    var imgFace = document.getElementById('face')
    context.drawImage(imgFace, x, y)

    if (canvas.height - y < 17) {
      // isFirst = false
      alert('恭喜你通關 遊戲結束')
      return false
    }
    // 這裏若是重置的話變成非自動移動,也就是每按下一次方向鍵只前進一步,因爲目前體驗很差因此先不作重置
    // dx = 0
    // dy = 0
  }
  setTimeout(drawFrame, 20)
}

上述代碼中,移動函數比較簡單,繪製幀的函數裏面比較重要的就是碰撞檢測函數,在下面詳細解釋。

碰撞檢測

要檢測物體與牆體是否碰撞,一般狀況是要先把地圖信息保存到內存裏,而後在移動物體時檢測是否與當前的某個牆體碰撞,可是因爲咱們的地圖背景是黑白迷宮,因此可使用顏色來檢測碰撞。具體的作法是:

獲取當前物體的座標位置,利用canvas檢測當前地圖上這個位置的顏色是否爲黑色,若是是,說是是牆體,不該該執行移動,下面就是代碼:

function checkForCollision() {
  var imageData = context.getImageData(x - 1, y - 1, 15 + 2, 15 + 2)
  var pixels = imageData.data

  for (var i = 0, len = pixels.length; i < len; i++) {
    var red = pixels[i],
        green = pixels[i + 1]
        blue = pixels[i + 2]
        alpha = pixels[i + 3]

    // 檢測是否碰到黑色的牆
    if (red === 0 && green === 0 && blue === 0) {
      return true
    }
  }
  return false
}

在這裏,15是小人的寬度,咱們檢測小人兩側各1px範圍(對應代碼中的getImageData(x - 1, y - 1, 15 + 2, 15 + 2)能夠稍微思考下這裏爲何是+2),若是是黑色,說明檢測到碰撞。

其他

在代碼裏,我加了一些其餘的功能,好比提示答案等。至於更換地圖也比較簡單:把地圖對應的文件地址,起點座標,答案圖片路徑等存在一個對象裏,而後設置一個地圖數組,點擊的時候切換地圖並從新渲染就能夠了。還有一些值得優化的地方,好比:

  1. 碰撞檢測在拐彎的地方體驗不佳;
  2. 當前狀況運行時有軌跡,在答案模式下應該如何去掉軌跡?

有興趣的同窗能夠試着本身實現下。

小結

這個例子相對比較簡單,對js的要求不高,拿來玩一下仍是挺不錯的。

而後依然是每次都同樣的結尾,若是內容有錯誤的地方歡迎指出;若是對你有幫助,歡迎點贊和收藏,轉載請徵得贊成後著明出處,若是有問題也歡迎私信交流,主頁有郵箱地址~溜了

相關文章
相關標籤/搜索