【JavaScript】貪喫蛇小遊戲

效果預覽:https://sevlt.github.io/snake-game/index.html

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
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章