日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

2048+html源码之家,前端纯原生代码实现2048

發布時間:2023/12/14 HTML 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2048+html源码之家,前端纯原生代码实现2048 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

為什么閑著沒事要做一個2048呢?還不是360前端星計劃(2018春招實習生)要我做的。然后就花了幾天時間做了一個2048小游戲,兼容到pc端和部分移動端(設備有限,有的移動瀏覽器真的沒兼容到或者是真的不想做兼容了)。僅供大家看看就好哈。

在線預覽:http://47.94.199.75/index.html (這個網址暫時有效。。以后點進去不知道又是我的什么實驗作品。)

游戲介紹

我做完給朋友看之后發現不是每個人都玩過這個游戲。簡單介紹一下游戲內容好了。

獲勝條件: 拼湊出一個2048方塊

失敗條件: 當前沒有可用方塊,并且所有方塊都不可以和臨近方塊合并

代碼結構

index.html:

游戲失敗

再來一局

#bg為背景圖,也就是空的灰色方塊,因為方塊移動的時候不能露出底下的空白

#main為實體,也就是游戲中我們看見的包含數字的方塊

#alert為提示框,一開始display:none,當游戲勝利或者結束的時候,display:block

#alert span 失敗消息或者勝利消息

css的話,主要是關于動畫元素的設置:

base.css

#main .item {

transition: all .3s ease-out;

-moz-transition: all .3s ease-out; /* Firefox 4 */

-webkit-transition: all .3s ease-out; /* Safari 和 Chrome */

-o-transition: all .3s ease-out; /* Opera */

left: 0px;

top: 0px;

}

js的話主要是兩塊,util.js負責了一些外圍函數(重要的是關于移動端滑動事件的封裝)的處理,2048.js就是頁面整體邏輯

util.js // 關于移動端滑動事件的封裝

const touchManager = (function () {

let start = []

let end = []

let timeStamp = 0

let manager = {}

manager.touchstart = function (event) { // 記錄下開始位置

event.stopPropagation()

timeStamp = event.timeStamp // 獲取點擊時的時間

let target = event.targetTouches[0]

start = [target.pageX, target.pageY]

end = [target.pageX, target.pageY]

console.log('start')

}

manager.touchmove = function (event) { // 記錄下移動位置

event.stopPropagation()

event.preventDefault()

let target = event.targetTouches[0]

end = [target.pageX, target.pageY]

console.log('move')

}

manager.touchend = function (event) { // 處理開始位置和移動位置給出滑動方向

event.stopPropagation()

event.preventDefault()

const abs = Math.abs

let time = event.timeStamp - timeStamp // 獲取滑動操作使用的時間

let moveX = end[0] - start[0]

let moveY = end[1] - start[1]

if (time > 500 || (abs(moveX) < 50 && abs(moveY) < 50)) { // 移動距離不夠或時間太長就不認為是滑動

return false

} else {

if (abs(moveX) >= abs(moveY)) { // 橫向移動距離較長

console.log(moveX)

return moveX > 0 ? 'right' : 'left'

} else { // 縱向移動距離較長

console.log(moveY)

return moveY > 0 ? 'down' : 'up'

}

}

}

return manager

})()

2048.js 主要由以下幾個數據結構和函數構成:

數據結構:

let data = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] // 初始化

let emptyList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] // 當前沒有元素的格子

const container = document.querySelector('#main') // 操作實體

const bg = document.querySelector('#bg') // 背景板

const alert = document.querySelector('#alert') // 提醒框

const alertText = alert.querySelector('span') // 提醒框里的文字容器

const baseSize = parseInt(getDomStyle(container).width) // 基礎畫板的size

let gameOver = false // 標志游戲是否結束

const animateTime = 300 // 單位ms, 動畫時長

這個地方保存了大量dom元素的引用,為了以后操作的時候減少獲取dom的性能消耗

另外還有以下幾個函數:

main // 主程序

resize(el) // 調整元素寬高一致

createElement() // 在emptyList里找1-2個下標出來,給data添加新的元素,取值為{2, 4}

paint(el, data) // 用data在el里畫出每一個格子

animate(move, arrow) // 傳入一個移動隊列,和移動方向‘left’代表橫向,‘top’代表縱向

isWin(data) isLost(data, emptyList) // 判斷游戲勝負

win() lost() // 顯示勝負消息

replay() // 再來一局

moveHandle = {...} // 封裝了計算移動結果的函數

然后再從主程序看函數的流程:

function main () { // 主程序

// 調整背景和實體寬高

resize(container)

resize(bg)

// 初始化背景和實體元素

paint(bg, data)

// 創建1-2個初始元素

createNewElement()

paint(container, data)

// 綁定事件監聽器

addEvent(window, 'keydown', function (event) { // 按鍵監聽

if (gameOver) {

return

}

let arrow = keyCodeMap[event.keyCode]

switch (arrow) {

case 'left':

case 'up':

case 'right':

case 'down': {

moveHandle.move(arrow)

break

}

}

})

addEvent(alert.querySelector('button'), 'click', replay) // 再玩一次

addEvent(container, 'touchstart', touchManager.touchstart)

addEvent(container, 'touchmove', touchManager.touchmove)

addEvent(container, 'touchend', function (event) {

let arrow = touchManager.touchend(event)

if (arrow) {

moveHandle.move(arrow)

}

})

}

也即是:1.初始化 2. 綁定事件監聽

然后就是如何計算出移動結果,以下用一個左滑計算(moveHandle.moveleft)為例子

moveleft: function () { // 向左移動

// 計算移動后的data

// 要移動的元素的移動坐標

// 沒有元素的格子

let newData = copy(data) // 獲取當前數據的一個copy

let move = [] // 方塊移動隊列

emptyList = []

for (let i = 0; i < 4; i++) { // 一行行處理

let newList = [] // 新行

let oldList = data[i]

for (let j = 0; j < 4; j++) { // 找到所有非0單元

let value = newData[i][j]

if (value !== 0) {

newList.push(value)

}

}

if (newList.length > 1) { // 合并同類項

for (let j = 0, len = newList.length; j < len - 1; j++) {

if (newList[j] === newList[j + 1]) {

newList[j] *= 2

newList[j + 1] = 0

j++

}

}

newList = newList.filter(item => item !== 0) // 過濾掉上一步產生的0

}

for (let j = newList.length; j < 4; j++) { // 補全數列尾部的0

emptyList.push(i * 4 + j)

newList.push(0)

}

newData[i] = newList

// 產生每位元素移動的坐標

for (let j = 0, k = 0,tag = false; j < 4; j++) { // j為舊元素位置,k為移動到的位置

if (newList[k] === 0) { // 如果沒有要移動的位置了

break

} else if (oldList[j] === newList[k]) { // j移動到k位置

if (j !== k) {

move.push({

start: [i, j],

end: [i, k]

})

}

k++

} else if (oldList[j] === newList[k] / 2) { // 兩個元素合成k位置的元素

move.push({

start: [i, j],

end: [i, k]

})

if (tag) {

k++

}

tag = !tag

}

}

}

return {

newData: newData,

move: move

}

}

這個函數最后產出的是 newData 計算后的 data, move 方塊的移動隊列,形如[{start: [x1, y1], end: [x2, y2]}, ... ]

然后怎么利用這個計算結果呢,看moveHandle.move.(moveHandle中有三個私有變量,moving鎖定句柄,防止動畫過程中用戶再次滑動,win是否勝利,lost時候失敗)

move: function (arrow) { // arrow = 移動方向

if (this.moving) { // 如果正在進行動畫,返回移動失敗

return false

}

let result = this['move' + arrow]() // 獲取移動計算后的結果

let newData = result.newData // 移動后的數據矩陣

let move = result.move // 移動元素列表

// 根據移動元素列表判斷該操作是否有效

if (move.length === 0) { // 沒有可以移動的元素,則無效

console.log('本次移動無效')

return false

}

// 進行0.3秒動畫

data = newData // 修改全局數據矩陣

createNewElement() // 創造新元素

// 判斷游戲勝負

this.win = isWin(newData)

if (!this.win) {

this.lost = isLost(newData, emptyList)

}

this.moving = true // 鎖定該事件句柄

setTimeout((function (self) {

animate(move, arrow)

return function () {

// 足夠時間后

self.moving = false // 終止動畫

paint(container, data) // 重繪視圖

// 判斷游戲勝負

if (self.win) { // 贏得了游戲

win()

} else if (self.lost) {

lost()

}

}

})(this), animateTime)

}

我自認為我的注釋內容還是挺多的,應該還是能看懂。這次分享就到這了。歡迎評論區留言討論。發現有什么bug也盡可能跟我說把。

BUG

目前已知的是:

1.微信內置瀏覽器的轉碼問題:

這個因為我懶得整一個域名,所以它為了安全就會進行轉碼,沒法游戲。也就不修復了。。只是個小玩具。

2.ios長按會選取文字而且無法取消:

這個問題我已經做了一定的修復,但是我沒復現這個問題的方法,也沒再處理

3.夸克瀏覽器自帶手勢導致左滑右滑會進行系統行為:

沒想到辦法,如果有人有辦法請告訴我,謝謝。

總結

以上是生活随笔為你收集整理的2048+html源码之家,前端纯原生代码实现2048的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。