Bootstrap

使用HTML+CSS+JS 实现贪吃蛇游戏

:阿余
:2022-3-2-2
:如有错误,敬请指正。感谢!

第一步 、计算地图大小,网页设置

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20;
    // 水平方向最大格子数
    const ROWS = 20;
    // 垂直方向最大格子数
    const COLUMNS = 20;
    // 获取地图元素
    let map = document.getElementById('map');
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px';
    map.style.height = COLUMNS * SIZE + 'px';
</script>

</html>

第二步、绘制贪吃蛇

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
    .snake-body{
        width:20px;
        height:20px;
        background:black;
        position:absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'
    
    
    
    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

     // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }
    drawSnake()
</script>

</html>

第三步、移动贪吃蛇

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
	.snake-body{
        width:20px;
        height:20px;
        background:black;
        position:absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'
    
    
    
    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

     // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }
    
    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]
    
    // 贪吃蛇移动函数
    function move() {
        
        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }
        
        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
    }
	
    // 定义一个运动函数
   	function run()
    {
        // 绘制贪吃蛇
        drawSnake()
        // 移动贪吃蛇
        move()
    }
    // 使用定时器让贪吃蛇移动起来
    setInterval(run,200)
</script>

</html>

第四步、改变贪吃蛇的移动方向

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }
	.snake-body{
        width:20px;
        height:20px;
        background:black;
        position:absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'
    
    
    
    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

     // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }
    
    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]
    
    // 贪吃蛇移动函数
    function move() {
        
        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }
        
        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
    }
	
    // 使用方向键,改变贪吃蛇的移动方向
    // ←↑→↓ 的键代码分别是 37,38,39,40
    // 移动方向规则,向右移动时候,无法直接向左移动,向上移动的时候,无法直接向下移动(即无法180反方向移动)
    // 通过方向数组 direction 来判断贪吃蛇的移动方向
    // 为窗口绑定 keydown 监听事件
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            // 左
            case 37:
                // 判断贪吃蛇是否没有向右移动
                if (direction[0] !== 1) direction = [-1, 0]
                break
            // 上
            case 38:
                // 判断贪吃蛇是否没有向下移动
                if (direction[1] !== 1) direction = [0, -1]
                break
            // 右
            case 39:
                // 判断贪吃蛇是否没有向左移动
                if (direction[0] !== -1) direction = [1, 0]
                break
            // 下
            case 40:
                // 判断贪吃蛇是否没有向上移动
                if (direction[1] !== -1) direction = [0, 1]
                break
        }
    }
    
    // 定义一个运动函数
   	function run()
    {
        // 绘制贪吃蛇
        drawSnake()
        // 移动贪吃蛇
        move()
    }
    // 使用定时器让贪吃蛇移动起来
    setInterval(run,200)
</script>

</html>

第五步、为贪吃蛇生成小零食

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    .snake-body {
        width: 20px;
        height: 20px;
        background: black;
        position: absolute;
    }

    .food {
        width: 20px;
        height: 20px;
        background: purple;
        position: absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'



    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

    // 定义两个变量,来存放食物出现的格子位置
    let foodX;
    let foodY;

    // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }

    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]

    // 贪吃蛇移动函数
    function move() {

        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }

        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
    }

    // 使用方向键,改变贪吃蛇的移动方向
    // ←↑→↓ 的键代码分别是 37,38,39,40
    // 移动方向规则,向右移动时候,无法直接向左移动,向上移动的时候,无法直接向下移动(即无法180反方向移动)
    // 通过方向数组 direction 来判断贪吃蛇的移动方向
    // 为窗口绑定 keydown 监听事件
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            // 左
            case 37:
                // 判断贪吃蛇是否没有向右移动
                if (direction[0] !== 1) direction = [-1, 0]
                break
            // 上
            case 38:
                // 判断贪吃蛇是否没有向下移动
                if (direction[1] !== 1) direction = [0, -1]
                break
            // 右
            case 39:
                // 判断贪吃蛇是否没有向左移动
                if (direction[0] !== -1) direction = [1, 0]
                break
            // 下
            case 40:
                // 判断贪吃蛇是否没有向上移动
                if (direction[1] !== -1) direction = [0, 1]
                break
        }
    }

    // 生成小零食的随机位置
    function createFood() {
        foodX = Math.ceil(Math.random() * (ROWS - 1))
        foodY = Math.ceil(Math.random() * (COLUMNS - 1))
    }

    function drawFood() {
        if (foodX === undefined) {
            createFood()
        }

        let foodHtml = `<div class="food" style="left:${foodX * SIZE}px;top:${foodY * SIZE}px;"></div>`
        map.innerHTML += foodHtml
    }
    // 定义一个运动函数
    function run() {
        // 绘制贪吃蛇
        drawSnake()
        drawFood()
        // 移动贪吃蛇
        move()
    }
    // 使用定时器让贪吃蛇移动起来
    setInterval(run, 200)
</script>

</html>

第六步、吃到零食后,改变零食的位置

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    .snake-body {
        width: 20px;
        height: 20px;
        background: black;
        position: absolute;
        z-index: 1;
    }

    .food {
        width: 20px;
        height: 20px;
        background: purple;
        position: absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'



    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

    // 定义两个变量,来存放食物出现的格子位置
    let foodX;
    let foodY;

    // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }

    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]

    // 贪吃蛇移动函数
    function move() {

        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }

        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
    }

    // 使用方向键,改变贪吃蛇的移动方向
    // ←↑→↓ 的键代码分别是 37,38,39,40
    // 移动方向规则,向右移动时候,无法直接向左移动,向上移动的时候,无法直接向下移动(即无法180反方向移动)
    // 通过方向数组 direction 来判断贪吃蛇的移动方向
    // 为窗口绑定 keydown 监听事件
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            // 左
            case 37:
                // 判断贪吃蛇是否没有向右移动
                if (direction[0] !== 1) direction = [-1, 0]
                break
            // 上
            case 38:
                // 判断贪吃蛇是否没有向下移动
                if (direction[1] !== 1) direction = [0, -1]
                break
            // 右
            case 39:
                // 判断贪吃蛇是否没有向左移动
                if (direction[0] !== -1) direction = [1, 0]
                break
            // 下
            case 40:
                // 判断贪吃蛇是否没有向上移动
                if (direction[1] !== -1) direction = [0, 1]
                break
        }
    }

    // 生成小零食的随机位置
    function createFood() {
        foodX = Math.ceil(Math.random() * (ROWS - 1))
        foodY = Math.ceil(Math.random() * (COLUMNS - 1))
    }
    // 渲染食物函数
    function drawFood() {
        if (foodX === undefined) {
            createFood()
        }

        let foodHtml = `<div class="food" style="left:${foodX * SIZE}px;top:${foodY * SIZE}px;"></div>`
        map.innerHTML += foodHtml
    }
    // 判断贪吃蛇是否吃到了小零食
    function eatFood() {
        // 获得贪吃蛇的蛇头 
        let snakeHeader = snakeArr[0];
        // 如果小零食的坐标和蛇头的坐标完全一致
        // 说明吃到了这个小零食
        if (snakeHeader.x === foodX && snakeHeader.y === foodY) {
            return true
        }
        return false
    }

    // 定义一个运动函数
    function run() {
        // 绘制贪吃蛇
        drawSnake()
        drawFood()

        // 如果贪吃蛇吃到了小零食,重新生成小零食的坐标
        if (eatFood()) {
            createFood()
        }
        // 移动贪吃蛇
        move()
    }
    // 使用定时器让贪吃蛇移动起来
    setInterval(run, 200)
</script>

</html>

第七步、为贪吃蛇增加一截身体

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    .snake-body {
        width: 20px;
        height: 20px;
        background: black;
        position: absolute;
        z-index: 1;
    }

    .food {
        width: 20px;
        height: 20px;
        background: purple;
        position: absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'



    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

    // 定义两个变量,来存放食物出现的格子位置
    let foodX;
    let foodY;

    // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }

    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]

    // 贪吃蛇移动函数
    function move() {

        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }

        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
    }

    // 使用方向键,改变贪吃蛇的移动方向
    // ←↑→↓ 的键代码分别是 37,38,39,40
    // 移动方向规则,向右移动时候,无法直接向左移动,向上移动的时候,无法直接向下移动(即无法180反方向移动)
    // 通过方向数组 direction 来判断贪吃蛇的移动方向
    // 为窗口绑定 keydown 监听事件
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            // 左
            case 37:
                // 判断贪吃蛇是否没有向右移动
                if (direction[0] !== 1) direction = [-1, 0]
                break
            // 上
            case 38:
                // 判断贪吃蛇是否没有向下移动
                if (direction[1] !== 1) direction = [0, -1]
                break
            // 右
            case 39:
                // 判断贪吃蛇是否没有向左移动
                if (direction[0] !== -1) direction = [1, 0]
                break
            // 下
            case 40:
                // 判断贪吃蛇是否没有向上移动
                if (direction[1] !== -1) direction = [0, 1]
                break
        }
    }

    // 为贪吃蛇增加一截身体
    function addBody() {
        // 获取到最后一截身体
        let lastBody = snakeArr[snakeArr.length - 1]

        // 创建一个新的身体对象

        let newBody = {
            x: lastBody.x,
            y: lastBody.y
        }
        // 将新的身体对象,添加到贪吃蛇数组中
        snakeArr.push(newBody)
    }


    // 生成小零食的随机位置
    function createFood() {
        foodX = Math.ceil(Math.random() * (ROWS - 1))
        foodY = Math.ceil(Math.random() * (COLUMNS - 1))
    }
    // 渲染食物函数
    function drawFood() {
        if (foodX === undefined) {
            createFood()
        }

        let foodHtml = `<div class="food" style="left:${foodX * SIZE}px;top:${foodY * SIZE}px;"></div>`
        map.innerHTML += foodHtml
    }
    // 判断贪吃蛇是否吃到了小零食
    function eatFood() {
        // 获得贪吃蛇的蛇头 
        let snakeHeader = snakeArr[0];
        // 如果小零食的坐标和蛇头的坐标完全一致
        // 说明吃到了这个小零食
        if (snakeHeader.x === foodX && snakeHeader.y === foodY) {
            return true
        }
        return false
    }

    // 定义一个运动函数
    function run() {
        // 绘制贪吃蛇
        drawSnake()
        drawFood()

        // 如果贪吃蛇吃到了小零食,重新生成小零食的坐标
        if (eatFood()) {
            createFood()
        }
        // 移动贪吃蛇
        move()
    }
    // 使用定时器让贪吃蛇移动起来
    setInterval(run, 200)
</script>

</html>

第八步、判断贪吃蛇是否撞墙了

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    .snake-body {
        width: 20px;
        height: 20px;
        background: black;
        position: absolute;
        z-index: 1;
    }

    .food {
        width: 20px;
        height: 20px;
        background: purple;
        position: absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'



    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

    // 定义两个变量,来存放食物出现的格子位置
    let foodX;
    let foodY;

    // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }

    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]


    // 定义一个变量, 用来存放定时器的id

    let clockId;

    // 贪吃蛇移动函数
    function move() {

        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }

        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
    }

    // 使用方向键,改变贪吃蛇的移动方向
    // ←↑→↓ 的键代码分别是 37,38,39,40
    // 移动方向规则,向右移动时候,无法直接向左移动,向上移动的时候,无法直接向下移动(即无法180反方向移动)
    // 通过方向数组 direction 来判断贪吃蛇的移动方向
    // 为窗口绑定 keydown 监听事件
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            // 左
            case 37:
                // 判断贪吃蛇是否没有向右移动
                if (direction[0] !== 1) direction = [-1, 0]
                break
            // 上
            case 38:
                // 判断贪吃蛇是否没有向下移动
                if (direction[1] !== 1) direction = [0, -1]
                break
            // 右
            case 39:
                // 判断贪吃蛇是否没有向左移动
                if (direction[0] !== -1) direction = [1, 0]
                break
            // 下
            case 40:
                // 判断贪吃蛇是否没有向上移动
                if (direction[1] !== -1) direction = [0, 1]
                break
        }
    }

    // 为贪吃蛇增加一截身体
    function addBody() {
        // 获取到最后一截身体
        let lastBody = snakeArr[snakeArr.length - 1]

        // 创建一个新的身体对象

        let newBody = {
            x: lastBody.x,
            y: lastBody.y
        }
        // 将新的身体对象,添加到贪吃蛇数组中
        snakeArr.push(newBody)
    }


    // 生成小零食的随机位置
    function createFood() {
        foodX = Math.ceil(Math.random() * (ROWS - 1))
        foodY = Math.ceil(Math.random() * (COLUMNS - 1))
    }
    // 渲染食物函数
    function drawFood() {
        if (foodX === undefined) {
            createFood()
        }

        let foodHtml = `<div class="food" style="left:${foodX * SIZE}px;top:${foodY * SIZE}px;"></div>`
        map.innerHTML += foodHtml
    }
    // 判断贪吃蛇是否吃到了小零食
    function eatFood() {
        // 获得贪吃蛇的蛇头 
        let snakeHeader = snakeArr[0];
        // 如果小零食的坐标和蛇头的坐标完全一致
        // 说明吃到了这个小零食
        if (snakeHeader.x === foodX && snakeHeader.y === foodY) {
            return true
        }
        return false
    }

    // 定义一个检测是否撞墙的函数
    function checkWall() {
        // 获取蛇头
        let snakeHeader = snakeArr[0]
        // 判断蛇头是否撞墙
        if (snakeHeader.x < 0 || snakeHeader.x >= ROWS || snakeHeader.y < 0 || snakeHeader.y >= COLUMNS) {
            // 提醒用户,游戏结束
            alert('游戏结束了')

            // 如果撞墙清除定时器
            clearInterval(clockId)
        }
    }

    // 定义一个运动函数
    function run() {
        // 绘制贪吃蛇
        drawSnake()
        drawFood()
        // 如果贪吃蛇吃到了小零食,
        if (eatFood()) {
            // 增加一截身体
            addBody()
            // 重新生成小零食的坐标
            createFood()
        }
        // 移动贪吃蛇
        move()
        // 判断蛇头是否撞墙
        checkWall()
    }
    // 使用定时器让贪吃蛇移动起来
    clockId = setInterval(run, 200)
</script>

</html>

第九步、判断贪吃蛇是否吃到自己了

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    .snake-body {
        width: 20px;
        height: 20px;
        background: black;
        position: absolute;
        z-index: 1;
    }

    .food {
        width: 20px;
        height: 20px;
        background: purple;
        position: absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'



    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

    // 定义两个变量,来存放食物出现的格子位置
    let foodX;
    let foodY;

    // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }

    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]


    // 定义一个变量, 用来存放定时器的id

    let clockId;

    // 贪吃蛇移动函数
    function move() {

        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }

        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
    }

    // 使用方向键,改变贪吃蛇的移动方向
    // ←↑→↓ 的键代码分别是 37,38,39,40
    // 移动方向规则,向右移动时候,无法直接向左移动,向上移动的时候,无法直接向下移动(即无法180反方向移动)
    // 通过方向数组 direction 来判断贪吃蛇的移动方向
    // 为窗口绑定 keydown 监听事件
    document.onkeydown = function (e) {
        switch (e.keyCode) {
            // 左
            case 37:
                // 判断贪吃蛇是否没有向右移动
                if (direction[0] !== 1) direction = [-1, 0]
                break
            // 上
            case 38:
                // 判断贪吃蛇是否没有向下移动
                if (direction[1] !== 1) direction = [0, -1]
                break
            // 右
            case 39:
                // 判断贪吃蛇是否没有向左移动
                if (direction[0] !== -1) direction = [1, 0]
                break
            // 下
            case 40:
                // 判断贪吃蛇是否没有向上移动
                if (direction[1] !== -1) direction = [0, 1]
                break
        }
    }

    // 为贪吃蛇增加一截身体
    function addBody() {
        // 获取到最后一截身体
        let lastBody = snakeArr[snakeArr.length - 1]

        // 创建一个新的身体对象

        let newBody = {
            x: lastBody.x,
            y: lastBody.y
        }
        // 将新的身体对象,添加到贪吃蛇数组中
        snakeArr.push(newBody)
    }


    // 生成小零食的随机位置
    function createFood() {
        foodX = Math.ceil(Math.random() * (ROWS - 1))
        foodY = Math.ceil(Math.random() * (COLUMNS - 1))
    }
    // 渲染食物函数
    function drawFood() {
        if (foodX === undefined) {
            createFood()
        }

        let foodHtml = `<div class="food" style="left:${foodX * SIZE}px;top:${foodY * SIZE}px;"></div>`
        map.innerHTML += foodHtml
    }
    // 判断贪吃蛇是否吃到了小零食
    function eatFood() {
        // 获得贪吃蛇的蛇头 
        let snakeHeader = snakeArr[0];
        // 如果小零食的坐标和蛇头的坐标完全一致
        // 说明吃到了这个小零食
        if (snakeHeader.x === foodX && snakeHeader.y === foodY) {
            return true
        }
        return false
    }

    // 定义一个检测是否撞墙的函数
    function checkWall() {
        // 获取蛇头
        let snakeHeader = snakeArr[0]
        // 判断蛇头是否撞墙
        if (snakeHeader.x < 0 || snakeHeader.x >= ROWS || snakeHeader.y < 0 || snakeHeader.y >= COLUMNS) {
            // 提醒用户,游戏结束
            alert('游戏结束了')

            // 如果撞墙清除定时器
            clearInterval(clockId)
        }
    }

    // 定义一个是否吃到自己的函数

    function checkSelf() {
        // 获取蛇头
        let snakeHeader = snakeArr[0]

        // 遍历蛇身

        for (let i = 1; i < snakeArr.length; i++) {
            // 判断蛇头是否和蛇身重合
            if (snakeHeader.x === snakeArr[i].x && snakeHeader.y === snakeArr[i].y) {
                alert('游戏结束了')
                clearInterval(clockId)
            }
        }
    }

    // 定义一个运动函数
    function run() {
        // 绘制贪吃蛇
        drawSnake()
        drawFood()
        // 如果贪吃蛇吃到了小零食,
        if (eatFood()) {
            // 增加一截身体
            addBody()
            // 重新生成小零食的坐标
            createFood()
        }
        // 移动贪吃蛇
        move()
        // 判断蛇头是否撞墙
        checkWall()
        // 判断蛇是否咬到了自己
        checkSelf()
    }
    // 使用定时器让贪吃蛇移动起来
    clockId = setInterval(run, 200)
</script>

</html>

第十步、优化可以180°改变移动方向的bug

如果贪吃蛇现在是向右移动,我们快速按下向邻的方向键(左键或者上键),然后按下左键就可以实现 180 掉头

这是因为,我们按下相邻方向键的时候,已经改变的贪食蛇的移动方向数组,但是贪吃蛇此刻还没有移动,然后再按下反方向键就可以逃过程序判断

解决方法:定义一个变量来记录转向移动的状态,如果按了方向键,就锁定改变方向的状态,等贪吃蛇成功移动后,再解锁

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>贪吃蛇</title>
</head>
<style>
    #map {
        border: 2px solid black;
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

    .snake-body {
        width: 20px;
        height: 20px;
        background: black;
        position: absolute;
        z-index: 1;
    }
	.snake-body:first-child{
        border-radius:50%;
        background-color:pink;
        z-index:2;
	}
    .food {
        width: 20px;
        height: 20px;
        background: purple;
        position: absolute;
    }
</style>

<body>
    <div id="map">

    </div>
</body>
<script>
    // 定义地图的相关数据
    // 设定一个小单元格子的大小为 20px,20px 的正方形
    const SIZE = 20
    // 水平方向最大格子数
    const ROWS = 20
    // 垂直方向最大格子数
    const COLUMNS = 20
    // 获取地图元素
    let map = document.getElementById('map')
    // 计算出并设置地图宽度和高度
    map.style.width = ROWS * SIZE + 'px'
    map.style.height = COLUMNS * SIZE + 'px'



    // 使用数组来定义贪吃蛇的身体,默认只有两截身体
    // 每个数组单元代表一截贪吃蛇的身体 
    // x 代表这截身体在水平方向第 x 个格子上
    // y 代表这截身体在垂直方向第 y 个格子上
    let snakeArr = [
        {
            x: 5,
            y: 1
        },
        {
            x: 4,
            y: 1
        }
    ]

    // 定义两个变量,来存放食物出现的格子位置
    let foodX;
    let foodY;

    // 贪吃蛇绘制函数
    function drawSnake() {
        // 拼凑蛇身的 html 字符串
        let snakeHtml = ''
        // 循环所有的蛇身,并计算出该蛇身所处的 left 和 top 偏移 (格子数 * 格子大小  + px)
        for (let i = 0; i < snakeArr.length; i++) {
            snakeHtml += `<div class="snake-body" style="left:${snakeArr[i].x * SIZE}px;top:${snakeArr[i].y * SIZE}px;"></div>`
        }
        // 将拼凑好的蛇身html  字符串,设置为 map 的 innerHTML,重新显示
        map.innerHTML = snakeHtml
    }

    // 定义一个数组,存放贪吃蛇的移动距离 , 0 号单元为贪吃蛇水平移动距离,1号单元为贪吃蛇垂直距离
    // 水平方向:0 为不移动,1 为向右移动一个格子,-1 为向左移动一个格子
    // 垂直方向:0 为不移动 1 为向下移动一个格子,-1 为向上移动一个格子
    // 默认为 [1,0] 即贪吃蛇默认向在水平方向,向右移动
    let direction = [1, 0]


    // 定义一个变量, 用来存放定时器的id

    let clockId;
    // 定义一个变量,用来记录是否等待转向
    let isTurn = false;

    // 贪吃蛇移动函数
    function move() {

        // 除贪吃蛇蛇头,每一截蛇身的位置等于前一个蛇身的位置 , 蛇身数组的0号单元就是蛇头,其余是蛇身
        // 循环贪吃蛇蛇身数组
        for (let i = snakeArr.length - 1; i > 0; i--) {
            // 让每一截蛇身的位置等于他的前一截蛇身的位置
            snakeArr[i].x = snakeArr[i - 1].x
            snakeArr[i].y = snakeArr[i - 1].y
        }

        // 将蛇头,按照贪吃蛇的移动方向增加一个格子
        snakeArr[0].x += direction[0]
        snakeArr[0].y += direction[1]
        isTurn = false
    }

    // 使用方向键,改变贪吃蛇的移动方向
    // ←↑→↓ 的键代码分别是 37,38,39,40
    // 移动方向规则,向右移动时候,无法直接向左移动,向上移动的时候,无法直接向下移动(即无法180反方向移动)
    // 通过方向数组 direction 来判断贪吃蛇的移动方向
    // 为窗口绑定 keydown 监听事件
    document.onkeydown = function (e) {
        if (isTurn) {
            return
        }
        switch (e.keyCode) {
            // 左
            case 37:
                // 判断贪吃蛇是否没有向右移动
                if (direction[0] !== 1) {
                    isTurn = true
                    direction = [-1, 0]
                }
                break
            // 上
            case 38:
                // 判断贪吃蛇是否没有向下移动
                if (direction[1] !== 1) {
                    isTurn = true
                    direction = [0, -1]
                }
                break
            // 右
            case 39:
                // 判断贪吃蛇是否没有向左移动
                if (direction[0] !== -1) {
                    isTurn = true
                    direction = [1, 0]
                }
                break
            // 下
            case 40:
                // 判断贪吃蛇是否没有向上移动
                if (direction[1] !== -1) {
                    isTurn = true
                    direction = [0, 1]
                }
                break
        }
    }

    // 为贪吃蛇增加一截身体
    function addBody() {
        // 获取到最后一截身体
        let lastBody = snakeArr[snakeArr.length - 1]

        // 创建一个新的身体对象

        let newBody = {
            x: lastBody.x,
            y: lastBody.y
        }
        // 将新的身体对象,添加到贪吃蛇数组中
        snakeArr.push(newBody)
    }


    // 生成小零食的随机位置
    function createFood() {
        foodX = Math.ceil(Math.random() * (ROWS - 1))
        foodY = Math.ceil(Math.random() * (COLUMNS - 1))
    }
    // 渲染食物函数
    function drawFood() {
        if (foodX === undefined) {
            createFood()
        }

        let foodHtml = `<div class="food" style="left:${foodX * SIZE}px;top:${foodY * SIZE}px;"></div>`
        map.innerHTML += foodHtml
    }
    // 判断贪吃蛇是否吃到了小零食
    function eatFood() {
        // 获得贪吃蛇的蛇头 
        let snakeHeader = snakeArr[0];
        // 如果小零食的坐标和蛇头的坐标完全一致
        // 说明吃到了这个小零食
        if (snakeHeader.x === foodX && snakeHeader.y === foodY) {
            return true
        }
        return false
    }

    // 定义一个检测是否撞墙的函数
    function checkWall() {
        // 获取蛇头
        let snakeHeader = snakeArr[0]
        // 判断蛇头是否撞墙
        if (snakeHeader.x < 0 || snakeHeader.x >= ROWS || snakeHeader.y < 0 || snakeHeader.y >= COLUMNS) {
            // 提醒用户,游戏结束
            alert('游戏结束了')

            // 如果撞墙清除定时器
            clearInterval(clockId)
        }
    }

    // 定义一个是否吃到自己的函数

    function checkSelf() {
        // 获取蛇头
        let snakeHeader = snakeArr[0]

        // 遍历蛇身

        for (let i = 1; i < snakeArr.length; i++) {
            // 判断蛇头是否和蛇身重合
            if (snakeHeader.x === snakeArr[i].x && snakeHeader.y === snakeArr[i].y) {
                alert('游戏结束了')
                clearInterval(clockId)
            }
        }
    }

    // 定义一个运动函数
    function run() {
        // 绘制贪吃蛇
        drawSnake()
        drawFood()
        // 如果贪吃蛇吃到了小零食,
        if (eatFood()) {
            // 增加一截身体
            addBody()
            // 重新生成小零食的坐标
            createFood()
        }
        // 移动贪吃蛇
        move()
        // 判断蛇头是否撞墙
        checkWall()
        // 判断蛇是否咬到了自己
        checkSelf()
    }
    // 使用定时器让贪吃蛇移动起来
    clockId = setInterval(run, 200)
</script>

</html>
;