Html 代碼:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="./style.css" /> <title>Snake</title> </head> <body> <div class="wrapper"> <div class="wrapper1"> <span style="font-size: 40px;">貪喫蛇</span><br /><br /><br /> <div id="diff" style="font-size: 20px;"> <span>難度:</span> <select onchange="this.blur()"> <option value="300">簡單</option> <option value="100">普通</option> <option value="50">困難</option> </select> </div> <br /> <div id="score" style="font-size: 20px;"><span>當前得分:</span><span>0</span></div> </div> <div class="tips">Tips:回車鍵以開始 / 暫停</div> <div class="wrapper2"> <div id="start"></div> <div id="map"> <div id="snakeHead"></div> </div> </div> </div> <script src="./main.js"></script> </body> </html>
CSS 代碼:
* { margin: 0; padding: 0; box-sizing: border-box; } body { width: 100%; height: 100vh; background-color: #f9fafb; } #start { position: absolute; width: 100%; height: 160px; border-radius: 5px; background-color: #4c4c4c; background-image: url(./Play.png); background-size: 150px 150px; background-repeat: no-repeat; background-position: center; opacity: 0.7; margin: auto; top: 0; bottom: 0; visibility: visible; z-index: 1; } .wrapper { border: 1px solid #c1c0bd; border-radius: 5px; box-shadow: -1px 5px 35px -9px rgba(0, 0, 0, 0.2); background-image: url(./bgimg.png); position: absolute; margin: auto; top: 0; bottom: 0; right: 0; left: 0; width: 1000px; height: 600px; } .wrapper1 { background-color: #fff; border: 1px solid #c1c0bd; border-radius: 5px; box-shadow: -1px 5px 35px -9px rgba(0, 0, 0, 0.2); position: absolute; font-family: Sans-serif; padding: 30px; top: 50px; left: 210px; margin-left: -90px; } .tips { position: absolute; bottom: 15px; left: 15px; font-size: 12px; } .wrapper2 { background-color: #fff; border: 1px solid #c1c0bd; border-radius: 5px; box-shadow: -1px 5px 35px -9px rgba(0, 0, 0, 0.2); position: absolute; height: 497px; width: 497px; top: 50px; right: 80px; } select { appearance: none; -moz-appearance: none; -webkit-appearance: none; width: 60px; height: 25px; outline: none; padding-left: 15px; border-radius: 5px; } #map { position: absolute; width: 495px; height: 495px; border-radius: 5px; } #snakeHead { position: absolute; width: 15px; height: 15px; background-color: #d3dace; top: 240px; left: 0; } .snakeBody { position: absolute; width: 15px; height: 15px; background-color: #aaa3a3; } .food { position: absolute; width: 15px; height: 15px; background-color: #da9999; }
JavaScript 代碼:
let theGame //定時器 let status = 'off' //遊戲是否開始 let isRunning = 0 //判斷遊戲是否在運行 addEventListener('keydown', (e) => { if (e.keyCode === 13) { startGame() } if (e.keyCode === 37 && isRunning === 1) { if (arrX.length === 1) { //爲長度爲1,此時可改變四個方向 direction = 'left' } else { direction = direction === 'right' ? 'right' : 'left' //長度不爲1時不可反向 } } else if (e.keyCode === 38 && isRunning === 1) { if (arrX.length === 1) { direction = 'up' } else { direction = direction === 'down' ? 'down' : 'up' } } else if (e.keyCode === 39 && isRunning === 1) { if (arrX.length === 1) { direction = 'right' } else { direction = direction === 'left' ? 'left' : 'right' } } else if (e.keyCode === 40 && isRunning === 1) { if (arrX.length === 1) { direction = 'down' } else { direction = direction === 'up' ? 'up' : 'down' } } }) function startGame() { if (status === 'off') { start.style.visibility = 'hidden' status = 'on' if (isRunning === 0) { init() isRunning = 1 } if (!foodNode) { addFood() } theGame = setInterval(move, time) } else { start.style.visibility = 'visible' status = 'off' clearInterval(theGame) } } let direction, arrX, arrY, tempX, tempY, arrFood = [], foodNode, time function init() { score.children[1].textContent = '0' time = diff.children[1].value - 0 direction = 'right' arrX = [0] arrY = [240] snakeHead.style.top = arrY[0] - 0 + 'px' snakeHead.style.left = arrX[0] - 0 + 'px' let node = map.children for (let i = node.length - 1; i >= 0; i--) { if (node[i].className === 'snakeBody') { map.removeChild(node[i]) } } } function addFood() { foodNode = document.createElement('span') foodNode.className = 'food' let count = 0 let num while (count != 2) { //生成兩次隨機數,分別作爲top、left num = parseInt(Math.round(Math.random() * 500) / 15) * 15 //15(蛇身)的倍數 if (num > 480) { continue } if (arrX.indexOf(num) === -1) { //若食物塊位置非蛇身,則添加 if (count === 0) { foodNode.style.left = num + 'px' } else { foodNode.style.top = num + 'px' } arrFood.push(num) count++ } } map.appendChild(foodNode) } function move() { let lastBodyX = arrX[arrX.length - 1] //記錄數組尾 let lastBodyY = arrY[arrY.length - 1] tempX = arrX[0] //記錄數組頭 tempY = arrY[0] if (direction === 'up' && arrY[0] - 15 >= 0) { snakeHead.style.top = arrY[0] - 15 + 'px' arrY[0] -= 15 } else if (direction === 'down' && arrY[0] + 15 <= 480) { snakeHead.style.top = arrY[0] + 15 + 'px' arrY[0] += 15 } else if (direction === 'left' && arrX[0] - 15 >= 0) { snakeHead.style.left = arrX[0] - 15 + 'px' arrX[0] -= 15 } else if (direction === 'right' && arrX[0] + 15 <= 480) { snakeHead.style.left = arrX[0] + 15 + 'px' arrX[0] += 15 } else { gameOver() return } if (arrX[0] === arrFood[0] && arrY[0] === arrFood[1]) { //喫到食物塊 score.children[1].textContent = score.children[1].textContent - 0 + 1 arrFood = [] //清空食物塊數組 let snakeBody = document.createElement('div') snakeBody.className = 'snakeBody' snakeBody.style.top = lastBodyY + 'px' snakeBody.style.left = lastBodyX + 'px' map.appendChild(snakeBody) arrX.push(lastBodyX) arrY.push(lastBodyY) map.removeChild(foodNode) addFood() } rebuildSnake() //重構蛇身 if (!hitMyself()) { gameOver() } } function gameOver() { start.style.visibility = 'visible' status = 'off' isRunning = 0 clearInterval(theGame) } function rebuildSnake() { let snake = map.getElementsByTagName('div') for (let i = snake.length - 1; i >= 1; i--) { if (i === 1) { //蛇脖子(蛇頭後緊挨着的方塊) snake[1].style.top = tempY + 'px' snake[1].style.left = tempX + 'px' arrY[1] = tempY arrX[1] = tempX break } //蛇神往前前進一格 snake[i].style.top = arrY[i - 1] + 'px' snake[i].style.left = arrX[i - 1] + 'px' //同時蛇身數組也要改變(前進一格) arrY[i] = arrY[i - 1] arrX[i] = arrX[i - 1] } } function hitMyself() { //判斷蛇頭是否撞擊到身體 let testX = arrX.slice(1) let testY = arrY.slice(1) for (let i = 0; i < testX.length; i++) { if (testX[i] === arrX[0] && testY[i] === arrY[0]) { return false } } return true }