基於Vue.js實現數字拼圖遊戲_javascript技巧

來源:互聯網
上載者:User

先來看看效果圖:

功能分析

當然玩歸玩,作為一名Vue愛好者,我們理應深入遊戲內部,一探代碼的實現。接下來我們就先來分析一下要完成這樣的一個遊戲,主要需要實現哪些功能。下面我就直接將此執行個體的功能點羅列在下了:

    1.隨機產生1~15的數字格子,每一個數字都必須出現且僅出現一次

    2.點擊一個數字方塊後,如其上下左右有一處為空白,則兩者交換位置

    3.格子每移動一步,我們都需要校正其是否闖關成功

    4.點擊重設遊戲按鈕後需對拼圖進行重新排序

以上便是本執行個體的主要功能點,可見遊戲功能並不複雜,我們只需一個個攻破就OK了,接下來我就來展示一下各個功能點的Vue代碼。

構建遊戲面板

作為一款以資料驅動的JS架構,Vue的HTML模板很多時候都應該綁定資料的,比如此遊戲的方塊格子,我們這裡肯定是不能寫死的,代碼如下:

<template>  <div class="box">    <ul class="puzzle-wrap">      <li         :class="{'puzzle': true, 'puzzle-empty': !puzzle}"         v-for="puzzle in puzzles"         v-text="puzzle"      ></li>    </ul>  </div></template><script>export default {  data () {    return {      puzzles: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]    }  }}</script>

這裡我省略了css樣式部分,大家可以先不用關心。以上代碼我們將1~15的數字寫死在了一個數組中,這顯然不是隨機排序的,那麼我們就來實現隨機排序的功能。

隨機排序數字

<template>  <div class="box">    <ul class="puzzle-wrap">      <li         :class="{'puzzle': true, 'puzzle-empty': !puzzle}"         v-for="puzzle in puzzles"         v-text="puzzle"      ></li>    </ul>  </div></template><script>export default {  data () {    return {      puzzles: []    }  },  methods: {    // 重設渲染    render () {      let puzzleArr = [],        i = 1      // 產生包含1 ~ 15數位數組      for (i; i < 16; i++) {        puzzleArr.push(i)      }      // 隨機打亂數組      puzzleArr = puzzleArr.sort(() => {        return Math.random() - 0.5      });      // 頁面顯示      this.puzzles = puzzleArr      this.puzzles.push('')    },  },  ready () {    this.render()  }}

以上代碼,我們利用for迴圈產生了一個1~15的有序數組,之後我們又利用原生JS的sort方法隨機打亂數字,這裡還包含了一個知識點就是Math.random()方法。

利用sort()方法進行自訂排序,我們需要提供一個比較函數,然後返回一個用於說明這兩個值的相對順序的數字,其傳回值如下:

    1.返回一個小於 0 的值,說明 a 小於 b

    2.返回 0,說明 a 等於 b

    3.返回一個大於 0 的值,說明 a 大於 b

這裡利用Math.random()產生一個 0 ~ 1 之間的隨機數,再減去0.5,這樣就會有一半機率返回一個小於 0 的值, 一半機率返回一個大於 0 的值,就保證了產生數組的隨機性,實現了動態隨機產生數字格子的功能。

需要注意的是,我們還在數組最後插了一個Null 字元串,用來產生唯一的空白欄框子。

交換方塊位置

<template>  <div class="box">    <ul class="puzzle-wrap">      <li         :class="{'puzzle': true, 'puzzle-empty': !puzzle}"         v-for="puzzle in puzzles"         v-text="puzzle"        @click="moveFn($index)"      ></li>    </ul>  </div></template><script>export default {  data () {    return {      puzzles: []    }  },  methods: {    // 重設渲染    render () {      let puzzleArr = [],        i = 1      // 產生包含1 ~ 15數位數組      for (i; i < 16; i++) {        puzzleArr.push(i)      }      // 隨機打亂數組      puzzleArr = puzzleArr.sort(() => {        return Math.random() - 0.5      });      // 頁面顯示      this.puzzles = puzzleArr      this.puzzles.push('')    },    // 點擊方塊    moveFn (index) {      // 擷取點擊位置及其上下左右的值      let curNum = this.puzzles[index],        leftNum = this.puzzles[index - 1],        rightNum = this.puzzles[index + 1],        topNum = this.puzzles[index - 4],        bottomNum = this.puzzles[index + 4]      // 和為空白的位置交換數值      if (leftNum === '') {        this.puzzles.$set(index - 1, curNum)        this.puzzles.$set(index, '')      } else if (rightNum === '') {        this.puzzles.$set(index + 1, curNum)        this.puzzles.$set(index, '')      } else if (topNum === '') {        this.puzzles.$set(index - 4, curNum)        this.puzzles.$set(index, '')      } else if (bottomNum === '') {        this.puzzles.$set(index + 4, curNum)        this.puzzles.$set(index, '')      }    }  },  ready () {    this.render()  }}</script>

    1.這裡我們首先在每個格子的li上添加了點擊事件@click="moveFn($index)",通過$index參數擷取點擊方塊在數組中的位置

    2.其次擷取其上下左右的數字在數組中的index值依次為index - 4、index + 4、index - 1、index + 1

    3.當我們找到上下左右有一處為空白的時候我們將空的位置賦值上當前點擊格子的數字,將當前點擊的位置置為空白

備忘:我們為什麼要使用$set方法,而不直接用等號賦值呢,這裡包含了Vue響應式原理的知識點。

// 因為 JavaScript 的限制,Vue.js 不能檢測到下面數組變化:// 1.直接用索引設定元素,如 vm.items[0] = {};// 2.修改資料的長度,如 vm.items.length = 0。// 為瞭解決問題 (1),Vue.js 擴充了觀察數組,為它添加了一個 $set() 方法:// 與 `example1.items[0] = ...` 相同,但是能觸發視圖更新example1.items.$set(0, { childMsg: 'Changed!'})

檢測是否闖關成功

<template>  <div class="box">    <ul class="puzzle-wrap">      <li         :class="{'puzzle': true, 'puzzle-empty': !puzzle}"         v-for="puzzle in puzzles"         v-text="puzzle"        @click="moveFn($index)"      ></li>    </ul>  </div></template><script>export default {  data () {    return {      puzzles: []    }  },  methods: {    // 重設渲染    render () {      let puzzleArr = [],        i = 1      // 產生包含1 ~ 15數位數組      for (i; i < 16; i++) {        puzzleArr.push(i)      }      // 隨機打亂數組      puzzleArr = puzzleArr.sort(() => {        return Math.random() - 0.5      });      // 頁面顯示      this.puzzles = puzzleArr      this.puzzles.push('')    },    // 點擊方塊    moveFn (index) {      // 擷取點擊位置及其上下左右的值      let curNum = this.puzzles[index],        leftNum = this.puzzles[index - 1],        rightNum = this.puzzles[index + 1],        topNum = this.puzzles[index - 4],        bottomNum = this.puzzles[index + 4]      // 和為空白的位置交換數值      if (leftNum === '') {        this.puzzles.$set(index - 1, curNum)        this.puzzles.$set(index, '')      } else if (rightNum === '') {        this.puzzles.$set(index + 1, curNum)        this.puzzles.$set(index, '')      } else if (topNum === '') {        this.puzzles.$set(index - 4, curNum)        this.puzzles.$set(index, '')      } else if (bottomNum === '') {        this.puzzles.$set(index + 4, curNum)        this.puzzles.$set(index, '')      }      this.passFn()    },    // 校正是否過關    passFn () {      if (this.puzzles[15] === '') {        const newPuzzles = this.puzzles.slice(0, 15)        const isPass = newPuzzles.every((e, i) => e === i + 1)        if (isPass) {          alert ('恭喜,闖關成功!')        }      }    }  },  ready () {    this.render()  }}</script>

我們在moveFn方法裡調用了passFn方法來進行檢測,而passFn方法裡又涉及了兩個知識點:

(1)slice方法

通過slice方法我們截取數組的前15個元素產生一個新的數組,當然前提了數組隨後一個元素為空白

(2)every方法

通過every方法我們來迴圈截取後數組的每一個元素是否等於其index+1值,如果全部等於則返回true,只要有一個不等於則返回false

如果闖關成功那麼isPass的值為true,就會alert "恭喜,闖關成功!"提示窗,如果沒有則不提示。

重設遊戲

重設遊戲其實很簡單,只需添加重設按鈕並在其上調用render方法就行了:

<template>  <div class="box">    <ul class="puzzle-wrap">      <li         :class="{'puzzle': true, 'puzzle-empty': !puzzle}"         v-for="puzzle in puzzles"         v-text="puzzle"        @click="moveFn($index)"      ></li>    </ul>    <button class="btn btn-warning btn-block btn-reset" @click="render">重設遊戲</button>  </div></template><script>export default {  data () {    return {      puzzles: []    }  },  methods: {    // 重設渲染    render () {      let puzzleArr = [],        i = 1      // 產生包含1 ~ 15數位數組      for (i; i < 16; i++) {        puzzleArr.push(i)      }      // 隨機打亂數組      puzzleArr = puzzleArr.sort(() => {        return Math.random() - 0.5      });      // 頁面顯示      this.puzzles = puzzleArr      this.puzzles.push('')    },    // 點擊方塊    moveFn (index) {      // 擷取點擊位置及其上下左右的值      let curNum = this.puzzles[index],        leftNum = this.puzzles[index - 1],        rightNum = this.puzzles[index + 1],        topNum = this.puzzles[index - 4],        bottomNum = this.puzzles[index + 4]      // 和為空白的位置交換數值      if (leftNum === '') {        this.puzzles.$set(index - 1, curNum)        this.puzzles.$set(index, '')      } else if (rightNum === '') {        this.puzzles.$set(index + 1, curNum)        this.puzzles.$set(index, '')      } else if (topNum === '') {        this.puzzles.$set(index - 4, curNum)        this.puzzles.$set(index, '')      } else if (bottomNum === '') {        this.puzzles.$set(index + 4, curNum)        this.puzzles.$set(index, '')      }      this.passFn()    },    // 校正是否過關    passFn () {      if (this.puzzles[15] === '') {        const newPuzzles = this.puzzles.slice(0, 15)        const isPass = newPuzzles.every((e, i) => e === i + 1)        if (isPass) {          alert ('恭喜,闖關成功!')        }      }    }  },  ready () {    this.render()  }}</script><style>@import url('./assets/css/bootstrap.min.css');body {  font-family: Arial, "Microsoft YaHei"; }.box {  width: 400px;  margin: 50px auto 0;}.puzzle-wrap {  width: 400px;  height: 400px;  margin-bottom: 40px;  padding: 0;  background: #ccc;  list-style: none;}.puzzle {  float: left;  width: 100px;  height: 100px;  font-size: 20px;  background: #f90;  text-align: center;  line-height: 100px;  border: 1px solid #ccc;  box-shadow: 1px 1px 4px;  text-shadow: 1px 1px 1px #B9B4B4;  cursor: pointer;}.puzzle-empty {  background: #ccc;  box-shadow: inset 2px 2px 18px;}.btn-reset {  box-shadow: inset 2px 2px 18px;}</style>

這裡我一併加上了css代碼。

總結

以上就是本文的全部內容,其實本遊戲的代碼量不多,功能點也不是很複雜,不過通過Vue來寫這樣的遊戲,有助於我們瞭解Vue以資料驅動的響應式原理,在簡化代碼量的同時也增加了代碼的可讀性。希望本文對大家學些Vue有所協助。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.