原生js 贪吃蛇

      /**

         * 大致思路:

         * 1. 创建一个长宽为500的画布

         * 2. 创建一个长宽为25的方格

         * 3. 计算出一行(一列)有多少格子

         * 4. 食物 :使用随机数(乘以最大格子数)

         * 5. 蛇 : 蛇的头部是随机数,如果吃了(食物)增长部分是蛇的(这次的位置)

         * 6. 蛇的移动 : 通过重新定义的addPlace{r ++ | --,c ++ | --} push进snake数组(重新绘制画面,从而改变蛇的位置)

         * 7. 蛇吃食物 : 蛇头移动到食物的位置(一样,不执行删除)

         * 8. 蛇撞墙 : 蛇头移动到墙的位置(执行Pause函数)

         * 9. 蛇撞自己 : 蛇头移动到蛇的尾巴的位置(执行Pause函数)

        * 10. 上下左右: 通过按钮key值判断向那个前进(不能按相反的按键)

        *      刚开始随机方向前进(通过判断)

        * 11. 撞到自己: 循环身体判断头部 r 和 c 是否一样(是则失败)

        */

css

   <style>
        * {
            padding: 0;
            margin: 0
        }

        body {
            height: 100vh;
            overflow: hidden;
            background-color: rgb(247, 90, 37);
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
        }

        #canvas {
            background: #fefcfc;
        }

        .contain__footer {
            display: flex;
        }

        button,
        .text {
            margin: 1rem;
            min-width: 5rem;
            height: 2.5rem;
            border-radius: 3vmin;
            background: rgb(245, 205, 112);
        }

        .text {
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 1.5rem;
            color: #000;
            font-size: 1rem;
            min-width: 8rem;
        }
    </style>

 html

    <div class="contain__footer">
        <div class="text"></div>
        <button class="begin">开始</button>
        <button class="pause">暂停</button>
    </div>
    <canvas id="canvas"></canvas>

Js

    <script>
        /**
         * 大致思路:
         * 1. 创建一个长宽为500的画布
         * 2. 创建一个长宽为25的方格
         * 3. 计算出一行(一列)有多少格子
         * 4. 食物 :使用随机数(乘以最大格子数)
         * 5. 蛇 : 蛇的头部是随机数,如果吃了(食物)增长部分是蛇的(这次的位置)
         * 6. 蛇的移动 : 通过重新定义的addPlace{r ++ | --,c ++ | --} push进snake数组(重新绘制画面,从而改变蛇的位置)
         * 7. 蛇吃食物 : 蛇头移动到食物的位置(一样,不执行删除)
         * 8. 蛇撞墙 : 蛇头移动到墙的位置(执行Pause函数)
         * 9. 蛇撞自己 : 蛇头移动到蛇的尾巴的位置(执行Pause函数)
        * 10. 上下左右: 通过按钮key值判断向那个前进(不能按相反的按键)
        *      刚开始随机方向前进(通过判断)
        * 11. 撞到自己: 循环身体判断头部 r 和 c 是否一样(是则失败)
        */
        // 一个小盒子 长宽
        let gridWH = 25;
        // 整个盒子的长宽
        let boxWH = 500;
        const canvas = document.getElementById('canvas');
        canvas.width = boxWH;
        canvas.height = boxWH;
        const ctx = canvas.getContext('2d');
        // 一行 有多少个盒子
        let rowColumn = boxWH / gridWH;
        // 计时器 存放
        let timing = null
        // 初始食物位置
        let food = {
            r: Math.floor(Math.random() * rowColumn),
            c: Math.floor(Math.random() * rowColumn),
        }

        // 贪吃蛇
        let snake = [{
            r: Math.floor(Math.random() * rowColumn),
            c: Math.floor(Math.random() * rowColumn),
        }]
        // 随机转向函数
        const getDivert = () => {
            let head = snake.at(-1)
            let randomDire = Math.floor(Math.random() * 2)
            if (head.r > rowColumn / 2) {
                if (food.c > rowColumn / 2) {
                    return randomDire ? 'up' : 'left'
                } else {
                    return randomDire ? 'down' : 'left'
                }
            } else {
                if (food.c > rowColumn / 2) {
                    return randomDire ? 'up' : 'right'
                } else {
                    return randomDire ? 'down' : 'right'
                }
            }
        }
        // 转向
        let divert = getDivert()
        //  显示器, 进行中 | 已暂停 | 已结束
        let state = document.querySelector('.text')
        // 绘制贪吃蛇        // 食物 图片
        const drawSnake = () => {
            const img = new Image();
            img.src = 'https://ts1.cn.mm.bing.net/th/id/R-C.ce37e3aeba0235882a4cbce008740f50?rik=1KQIPHuVZasYmw&riu=http%3a%2f%2fimage.huahuibk.com%2fuploads%2f20190228%2f22%2f1551363575-xTatlDnCwi.jpg&ehk=Yaculj3h0W%2fRw2n0uImmsIUVv9kzHg%2bP7spQwzw8xzk%3d&risl=&pid=ImgRaw&r=0';
            // 食物位置
            if (img.src) {
                if (food.r == snake[snake.length - 1].r && food.c == snake[snake.length - 1].c) {
                    food = {
                        r: Math.floor(Math.random() * rowColumn),
                        c: Math.floor(Math.random() * rowColumn),
                    }
                    img.onload = function () {
                        ctx.drawImage(img, food.r * gridWH, food.c * gridWH, gridWH, gridWH)
                    }
                    return
                }
                img.onload = function () {
                    ctx.drawImage(img, food.r * gridWH, food.c * gridWH, gridWH, gridWH)
                }
            } else {
                ctx.fillRect(food.r * gridWH, food.r * gridWH, gridWH, gridWH)
            }
        }
        // 盒子
        const box = () => {
            // 绘制表格
            for (let i = 0; i < rowColumn; i++) {
                ctx.beginPath();
                ctx.moveTo(i * gridWH, 0);
                ctx.lineTo(i * gridWH, boxWH);
                ctx.lineWidth = 1;
                ctx.stroke();
            }
            for (let i = 0; i < rowColumn; i++) {
                ctx.beginPath();
                ctx.moveTo(0, i * gridWH);
                ctx.lineTo(boxWH, i * gridWH);
                ctx.lineWidth = 1;
                ctx.stroke();
            }
            //  绘制食物
            drawSnake();
            //   要移除的坐标
            let removePlaceX = snake[0].r
            let removePlaceY = snake[0].c
            //  贪吃蛇头部
            let head = snake[snake.length - 1]
            // 不和snake数组关联
            let addPlace = { r: 0, c: 0 }
            if (divert == 'up') addPlace = { r: head.r, c: head.c - 1 }
            if (divert == 'down') addPlace = { r: head.r, c: head.c + 1 }
            if (divert == 'right') addPlace = { r: head.r + 1, c: head.c }
            if (divert == 'left') addPlace = { r: head.r - 1, c: head.c }
            //  当大于等于盒子格子数 |  小于  0   =>   游戏结束
            if (head.c < 0 || head.c >= rowColumn || head.r < 0 || head.r >= rowColumn) {
                clickPause("撞墙了,刷新重新开始")
                return
            } else {
                impact(addPlace)
                snake.push(addPlace)
                if (food.r != addPlace.r || food.c != addPlace.c) {
                    if (food.r == head.r && food.c == head.c) return
                    snake.shift()
                    ctx.clearRect(removePlaceX * gridWH, removePlaceY * gridWH, gridWH, gridWH);
                }
                // 图片
                for (let i = 0; i < snake.length; i++) {
                    ctx.fillStyle = i == snake.length - 1 ? 'rgb(70, 108, 40)' : 'rgb(170, 209, 10)'
                    ctx.fillRect(snake[i].r * gridWH, snake[i].c * gridWH, gridWH, gridWH)
                }

            }
        }
        // 开始
        document.querySelector('.begin').addEventListener('click', () => {
            timing = setInterval(box, 300)
            state.textContent = "进行中"
        })
        // 失败
        const clickPause = (value) => {
            clearInterval(timing)
            state.textContent = `${value}`
        }
        document.querySelector('.pause').addEventListener('click', () => {
            clearInterval(timing)
            state.textContent = `暂停,点击开始继续`
        })
        // 上下左右
        document.addEventListener('keydown', (e) => {
            if (e.key == 'ArrowUp' && divert != 'down') divert = 'up'
            if (e.key == 'ArrowDown' && divert != 'up') divert = 'down'
            if (e.key == 'ArrowLeft' && divert != 'right') divert = 'left'
            if (e.key == 'ArrowRight' && divert != 'left') divert = 'right'
        })
        // 是否撞到自己
        const impact = (addPlace) => {
            for (let j = 0; j < snake.length; j++) {
                if (addPlace.r == snake[j].r && addPlace.c == snake[j].c) {
                    clickPause(`撞到自己人了,刷新重新开始`)
                }
            }
        }
        // 初始值
        box()
    </script>

有更多想法请评论,感谢了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值