前言
這次使用了 vue 來編寫 2048,主要目的是溫習一下 vue。
但是好像沒有用到太多 vue 的東西,==! 估計可能習慣了不用框架吧
之前由于時間關系沒有對實現過程詳細講解,本次會詳細講解下比較繞的函數
由于篇幅問題簡單的函數就不做詳解了
代碼地址: https://github.com/yhtx1997/S...
實現功能數字合并
當前總分計算
沒有可移動的數字時不進行任何操作
沒有可移動,可合并的數字,并且不能新建時游戲失敗
達到 2048 結束游戲
用到的知識ES6
vue 部分模板語法
vue 生命周期
數組方法
reverse()
push()
unshift()
some()
forEach()
reduceRight()
數學方法
Math.abs()
Math.floor()
具體實現是否需要將上下操作轉換為左右操作
數據初始化
合并數字
判斷操作是否無效
渲染到頁面
隨機創建數字
計算總分
判斷成功
判斷失敗
總體流程如下所示
command (keyCode) { // 總部 this.WhetherToRotate(keyCode) // 是否需要將上下操作轉換為左右操作 this.Init() // 數據初始化 合并數字 this.IfInvalid() // 判斷是否無效 this.Rendering(keyCode) // 渲染到頁面 }初始化
首先先將基本的 HTML 標簽跟 CSS 樣式寫出來
由于用的 vue ,所以渲染 html 部分的代碼不用我們去手寫
總分: {{this.total}} 分// {{}} 這個中間表示 JavaScript 表達式// v-for表示循環渲染當前元素,具體渲染次數為 arr.length{{item>0?item:""}}// :class= 表示將 JavaScript 變量作為類名
css由于太長就不放了跟之前基本沒有太多區別
接下來是數據的初始化
data () { return { arr: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], // 與頁面綁定的數組 Copyarr: [[], [], [], []], // 用來數據操作的數組 initData: [], // 包含數字詳細坐標的數組 haveGrouping: false, // 有可以合并的數字 itIsLeft: false, // 是否為向左合并,默認不是向左合并 endGap: true, // 判斷最邊上有沒有空隙 默認有空隙 middleGap: true, // 真 為某行中間有空隙 haveZero: true, // 當前頁面有沒有 0 total: 0, // 總分數 itIs2048: false, // 是否成功 max: 2048 // 最高分數 } }
做好初始化看起來應該是這樣的效果
在 mounted 添加事件監聽
為什么在 mounted 添加事件?
我們先了解下vue的生命周期
beforeCreate 實例創建之前 在這個階段我們寫的代碼還沒有被運行
created 實例創建之后 在這個階段我們寫的代碼已經運行了但是還沒有將 HTML 渲染到頁面
mounted 掛載之后 在這個階段 html 渲染到頁面了,可以取到 dom 節點
beforeUpdate 數據更新前 在我們需要重新渲染 html 前調用 類似執行 warp.innerHTML = html; 之前
updated 數據更新后 在重新渲染 HTML 后調用
destroyed 實例銷毀后調用 將我們寫的代碼丟棄掉后調用
errorCaptured 當捕獲一個來自子孫組件的錯誤時被調用 2.5.0+ 新增
注:我說的我們寫的代碼只是一種代指,是為了方便理解,并不是真正的指我們寫的代碼
所以如果太早的話可能找不到 dom 節點,太晚的話,可能不能第一時間進行事件的響應
mounted () { window.onkeydown = e => { switch (e.keyCode) { case 37: // ← console.log("←") this.Command(e.keyCode) break case 38: // ↑ console.log("↑") this.Command(e.keyCode) break case 39: // → this.Command(e.keyCode) console.log("→") break case 40: // ↓ console.log("↓") this.Command(e.keyCode) break } } }將操作簡化為只有左右
這段代碼我是某天半夢半醒想到的,可能思維不好轉過來,可以看看代碼下面的圖
這樣一來就將向上的操作轉換成了向左的操作
向下的操作就轉換成了向右的操作
這樣折騰下可以少寫一半的數字合并代碼
WhetherToRotate (keyCode) { // 是否需要將上下操作轉換為左右操作 if (keyCode === 38 || keyCode === 40) { // 38 是上 40 是下 this.Copyarr = this.ToRotate(this.arr) } else if (keyCode === 37 || keyCode === 39) { // 37 是左 39 是右 [...this.Copyarr] = this.arr } // 將當前操作做一個標識 if (keyCode === 37 || keyCode === 38) { // 數據轉換后只有左右操作 this.itIsLeft = true } else if (keyCode === 39 || keyCode === 40) { this.itIsLeft = false } }
轉換代碼
ToRotate (arr) { // 將數據從 x 到 y y 到 x 相互轉換 let afterCopyingArr = [[], [], [], []] for (let i = 0; i < arr.length; i++) { for (let j = 0; j < arr[i].length; j++) { afterCopyingArr[i][j] = arr[j][i] } } return afterCopyingArr }數據初始化
數組中的 0 在這個小作品中僅用作占位,視為垃圾數據,所以開始前需要處理掉,在結束后再加上
兩種數據格式,一種是包含詳細信息的,用來做一些判斷; 一種是純數字的二維數組,之后用來從新渲染頁面
Init () { // 數據初始化 this.initData = this.DataDetails() // 非零數字詳情 this.Copyarr = this.NumberMerger() // 數字合并 }判斷是否無效
IfInvalid () { // 判斷是否無效 // 判斷每行中間有沒有空隙 this.MiddleGap() // 真 為某行中間有空隙 this.EndPointGap() // 在沒有中間空隙的條件下去判斷最邊上有沒有空隙 }
判斷兩個數字之間有沒有空隙
MiddleGap () { // 檢查每行中間有沒有空隙 // 當所有的數都是挨著的,那么 x 下標兩兩相減并除以組數得到的絕對數是 1 ,比他大說明中間有空隙 // 先將 x 下標兩兩相減 并添加到新的數組 let subarr = [[], [], [], []] // 兩兩相減的數據 let sumarr = [] // 處理后的最終數據 this.initData.forEach((items, index) => { items.forEach((item, i) => { if (typeof items[i + 1] !== "undefined") { subarr[index].push(item.col - items[i + 1].col) } }) }) // 將每一行的結果相加得到總和 然后除以每一行結果的長度 subarr.forEach((items) => { sumarr.push(items.reduceRight((a, b) => a + b, 0)) }) sumarr = sumarr.map((item, index) => Math.abs(item / subarr[index].length)) // 最后判斷有沒有比 1 大的值 sumarr.some(item => item > 1) this.middleGap = sumarr.some(item => item > 1) // 真 為 有中間空隙 }
判斷數字有沒有到最邊上
EndPointGap () { // 檢查最邊上有沒有空隙 // 判斷是向左還是向右 因為左右的判斷是不一樣的 this.endGap = true let end let initData = this.initData if (this.itIsLeft) { end = 0 this.endGap = initData.some(items => items.length !== 0 ? items[0].col !== end : false) } else { end = 3 this.endGap = initData.some(items => items.length !== 0 ? items[items.length - 1].col !== end : false) } // 取出每行的第一個數的 x 下標 // 判斷是不是最邊上 // 有不是的 說明邊上 至少有一個空隙 // 是的話說明邊上沒有空隙 }
這樣就將基本的判斷是否有效,是否失敗的條件都得到了
至于是否有可合并數字已經在數據初始化時就得到了
現在所有數據應該是這樣的
Rendering (keyCode) { this.AddZero() // 先將占位符加上 // 因為之前的數據都處理好了 所以只需要將上下的數據轉換回去就好了 if (keyCode === 38 || keyCode === 40) { // 38 是上 40 是下 this.Copyarr = this.ToRotate(this.Copyarr) } if (this.haveGrouping || this.endGap || this.middleGap) { // 滿足任一條件就說明可以新建隨機數字 this.RandomlyCreate(this.Copyarr) } else if (this.haveZero) { // 都不滿足 但是有空位不做失敗判斷 } else { // 以上都不滿足視為沒有空位,不可合并 if (this.itIs2048) { // 判斷是否達成2048 this.RandomlyCreate(this.Copyarr) alert("恭喜達成2048!") // 下面注釋掉的可讓游戲在點擊彈框按鈕后重新開始新游戲 // this.arr = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] // this.RandomlyCreate(this.arr) } else { //以上都不滿足視為失敗 this.RandomlyCreate(this.Copyarr) alert("游戲結束!") // this.arr = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] // this.RandomlyCreate(this.arr) } } if (this.itIs2048) { // 每次頁面渲染完,都判斷是否達成2048 this.RandomlyCreate(this.Copyarr) alert("恭喜達成2048!") // this.arr = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] // this.RandomlyCreate(this.arr) } }
隨機空白處創建數字
這里之前是用遞歸函數的形式去判斷,但是用遞歸函數的話會有很多問題,最大的問題就是可能會堆棧溢出,或者卡死(遞歸函數就是在函數的最后還會去調用自己,如果不給出 return 的條件,很容易堆棧溢出或卡死)
所以這次改成抽獎的模式,將所有的空位的坐標取到,放入一個數組,然后取這個數組的隨機下標,這樣我們會得到一個空位的坐標,然后再對這個空位進行處理
RandomlyCreate (Copyarr) { // 隨機空白處創建新數字 // 判斷有沒有可以新建的地方 let max = this.max let copyarr = Copyarr let zero = [] // 做一個抽獎的箱子 let subscript = 0 // 做一個拿到的獎品號 let number = 0 // 獎品號兌換的物品 // 找到所有的 0 將下標添加到新的數組 copyarr.forEach((items, index) => { items.forEach((item, i) => { if (item === 0) { zero.push({ x: index, y: i }) } }) }) // 取隨機數 然后在空白坐標集合中找到它 subscript = Math.floor(Math.random() * zero.length) if (Math.floor(Math.random() * 10) % 3 === 0) { number = 4 // 三分之一的機會 } else { number = 2 // 三分之二的機會 } if (zero.length) { Copyarr[zero[subscript].x][zero[subscript].y] = number this.arr = Copyarr } this.total = 0 this.arr.forEach(items => { items.forEach(item => { if (item === max && !this.itIs2048) { this.itIs2048 = true } this.total += item }) }) }
以上就是本次 2048 的主要代碼
最后,因為隨機出現4的幾率我改的比較大,所以相應的降低了一些難度,具體體現在當所有數字都在左邊(最邊上),且數字與數字間沒有空隙,再按左也會生成數字
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/101236.html
摘要:前言前段時間發現網上有很多收費或公開課都有教用做小游戲的,然后自己就也想動手做一個,做這個小游戲主要是為了鍛煉自己的邏輯能力,也算是對之前一些學習的總結吧注實現方法完全是自己邊玩邊想的,所有些亂還請見諒另外配色方案是在某個游戲截屏,然后用吸 前言 前段時間發現網上有很多收費或公開課都有教用 js 做 2048 小游戲的,然后自己就也想動手做一個,做這個小游戲主要是為了鍛煉自己的邏輯能力...
摘要:往期回顧在上一期的前端特效里,我們已經把果汁混合的效果里面的圓形菜單做好了,如果你錯過了上篇文章今天我們要討論的是杯子里面的液體生成問題先來回顧下咱們的果汁混合效果吧果汁混合效果,掃描下方二維碼就看到啦我們接著上期的內容來繼續往下講吧,本期 往期回顧 在上一期的【前端特效】?里,我們已經把果汁混合的效果里面的圓形菜單做好了,如果你錯過了上篇文章今天我們要討論的是杯子里面的液體生成問題 ...
摘要:微信應用號小程序資源匯總。每天不定期整理和收集微信小程序相關資源,方便查閱和學習,歡迎大家提交新的資源,完善和補充。 wechat-weapp-resource 微信應用號(小程序)資源匯總。 每天不定期整理和收集微信小程序相關資源,方便查閱和學習,歡迎大家提交新的資源,完善和補充。 showImg(https://segmentfault.com/img/remote/1460000...
摘要:微信應用號小程序資源匯總。每天不定期整理和收集微信小程序相關資源,方便查閱和學習,歡迎大家提交新的資源,完善和補充。 wechat-weapp-resource 微信應用號(小程序)資源匯總。 每天不定期整理和收集微信小程序相關資源,方便查閱和學習,歡迎大家提交新的資源,完善和補充。 showImg(https://segmentfault.com/img/remote/1460000...
閱讀 1814·2021-10-09 09:44
閱讀 2690·2021-09-22 15:38
閱讀 2451·2021-09-09 09:33
閱讀 686·2021-09-07 09:58
閱讀 1785·2021-09-02 15:41
閱讀 2485·2019-08-30 15:55
閱讀 1796·2019-08-30 15:55
閱讀 533·2019-08-30 15:44