原生js+canvas实现贪吃蛇小游戏

最近想学学WebGL就回过头把canvas标签看了看,顺便写了个小蛇玩玩。
注意点:

  1. 随机生成食物块;
    let fx = parseInt(Math.random() * 56) * 9 + 1;
    let fy = parseInt(Math.random() * 56) * 9 + 1;
    food = [fx, fy, 8, 8];
    其实这里可以根据画布大小将食物的分布区域进行修改(修改56数值)
    另外为了好看,每节蛇的身体是8*8的小块,小块间有1个单位的距离,小蛇和食物块也距离边界有1个单位的距离;
  2. 从中心区域生成初始小蛇(长度为3,蛇的长度可以用(分数值+30)/10 确定);
  3. 方向问题,用键盘的方向键keycode表示方向,默认向右,要注意蛇不能向反方向运动即蛇头向右的情况下只能改变方向为上或者下。
  4. 关键!!!!!小蛇的身体如何沿着头部走过的路径移动,同时吃到食物需要增加一节,因此需要确定一个数组,这里有个小的注意点就是,因为身体一直在增加,所以为了保证数组第一项一直是头部(因为后面的撞墙和撞到自己都需要用头部判断)所以不能用arr.push()而是用arr.unshift()方法。整个逻辑无论是撞墙还是撞到自己以及吃掉食物都是通过坐标来判断。具体见代码,有什么问题欢迎留言交流!
<!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>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        html,
        body {
            height: 100%;
            overflow: hidden;
        }

        body {
            background-color: aliceblue;
        }

        #box {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;

        }

        #other {
            width: 500px;
            display: flex;
            font-display: row;
            justify-content: space-around;
            margin: 10px 0;
        }

        h1 {
            margin-top: 20px;
            font-family: 'YouYuan', 'Courier New', Courier, monospace;
        }

        div div span {
            font-size: 25px;
            font-weight: 700;
        }

        select {
            position: relative;
            top: -3px;
            left: -10px;
            width: 70px;
            height: 30px;
            background-color: rgb(255, 255, 255);
            font-size: 15px;
            text-align: center;
            border-radius: 5px;
        }

        #beginBtn {
            padding: 6px;
            font-size: 15px;
            background-color: rgb(182, 175, 247);
            border-radius: 5px;
            cursor: pointer;
        }

        #test {
            background-color: rgb(180, 240, 172);
            border: 6px dashed black;
        }

        #text {
            margin: 15px 0;
            font-family: 'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif
        }
    </style>
</head>

<body onload="begin()">
    <div id="box">
        <h1>🐍宇宙超级无敌贪吃蛇🐍</h1>
        <div id="other">
            <span id="fraction">得分:0</span>
            <span id="difficulty">
                难度:
                <select size='1'>
                    <option value="500">--简单--</option>
                    <option value="200" selected>--普通--</option>
                    <option value="100">--困难--</option>
                    <option value="20">--地狱--</option>
                </select>
            </span>
            <button id="beginBtn">重新开始</button>
        </div>
        <canvas id="test">
            <span>浏览器不支持,请更换浏览器</span>
        </canvas>
        <p id="text">游戏说明:方向键控制宇宙无敌超级贪吃蛇运动方向。</p>
    </div>

    <script type="text/javascript">
        let state = true;//蛇状态(false死亡,true正常)
        let difficulty = document.querySelector('select').value;
        difficulty = 200;
        //重新开始点击事件
        let beginBtn = document.getElementById('beginBtn');
        let r = beginBtn.onclick = function () {
            if (state === false) {
                begin(difficulty);
            } else {
                location.reload();
            }
        }

        //难度选择
        document.querySelector('select').addEventListener('change', () => {
            difficulty = document.querySelector('select').value;
            document.querySelector('select').blur();
            if (state === false) {
                begin(difficulty);
            } else {
                alert('请先结束本局游戏!');
            }
        })

        let begin = function (time) {
            time = difficulty;
            // 拿到画布
            var testNode = document.querySelector('#test');
            if (testNode.getContext) {//最好判断以下支不支持此方法
                var ctx = testNode.getContext('2d');
                let width = 505;//区域/画布大小
                let height = 505;//区域/画布大小
                let direction = 39;//方向,默认向右为39
                let fraction = 0;//分数
                let bodys = [];//身体数组
                let food = [];//食物
                let headx = 253;
                let heady = 253;

                testNode.width = width;
                testNode.height = height;
                //初始化执行一次食物函数
                drawFoods();

                //键盘控制方向
                window.onkeydown = function (e) {
                    if (e.keyCode == 38) {
                        direction != 40 ? direction = 38 : direction = 40;
                    } else if (e.keyCode == 39) {
                        direction != 37 ? direction = 39 : direction = 37;
                    } else if (e.keyCode == 40) {
                        direction != 38 ? direction = 40 : direction = 38;
                    } else if (e.keyCode == 37) {
                        direction != 39 ? direction = 37 : direction = 39;
                    }
                }

                //绘制身体
                function draw() {
                    ctx.save();
                    ctx.fillStyle = 'black'
                    ctx.beginPath();
                    //改变方向
                    if (direction == 39) {
                        let body = [headx += 9, heady, 8, 8]
                        bodys.unshift(body);
                        if (bodys.length > (fraction + 30) / 10) {
                            bodys.pop();
                        }
                    } else if (direction == 38) {
                        let body = [headx, heady -= 9, 8, 8]
                        bodys.unshift(body);
                        if (bodys.length > (fraction + 30) / 10) {
                            bodys.pop();
                        }
                    } else if (direction == 37) {
                        let body = [headx -= 9, heady, 8, 8]
                        bodys.unshift(body);
                        if (bodys.length > (fraction + 30) / 10) {
                            bodys.pop();
                        }
                    } else if (direction == 40) {
                        let body = [headx, heady += 9, 8, 8]
                        bodys.unshift(body);
                        if (bodys.length > (fraction + 30) / 10) {
                            bodys.pop();
                        }
                    }
                    //判断是否咬到自己
                    let copyBodys = bodys.slice(1)
                    for (let j = 0; j < copyBodys.length; j++) {
                        if (copyBodys[j][0] == bodys[0][0] && copyBodys[j][1] == bodys[0][1]) {
                            state = false;
                            clearInterval(timer);
                            alert('笨蛇,咬到自己了!');
                        }
                    }
                    // 判断是否撞墙
                    if (bodys[0][0] < 1 || bodys[0][0] > width - 9 || bodys[0][1] < 1 || bodys[0][1] > height - 9) {
                        state = false;
                        clearInterval(timer);
                        alert('笨蛇,吃东西也要看路呀!');
                    }
                    for (let i = 0; i < bodys.length; i++) {
                        ctx.fillRect(bodys[i][0], bodys[i][1], bodys[i][2], bodys[i][3]);
                    }
                    ctx.stroke();
                    ctx.save();
                    ctx.fillStyle = '#BB1515';
                    ctx.beginPath();
                    ctx.fillRect(food[0], food[1], food[2], food[3]);
                    ctx.stroke();
                    //判断是否吃到食物
                    if (bodys[0][0] == food[0] && bodys[0][1] == food[1]) {
                        fraction += 10;
                        let fractionSpan = document.getElementById('fraction');
                        fractionSpan.innerHTML = `得分:${fraction}`;
                        drawFoods();
                    }


                }

                //产生食物
                function drawFoods() {
                    ctx.save();
                    ctx.beginPath();
                    let fx = parseInt(Math.random() * 56) * 9 + 1;
                    let fy = parseInt(Math.random() * 56) * 9 + 1;
                    food = [fx, fy, 8, 8];
                    ctx.fillRect(food[0], food[1], food[2], food[3]);
                    ctx.stroke();
                }

                //动画
                let timer = setInterval(() => {
                    ctx.clearRect(0, 0, testNode.width, testNode.height);
                    draw();
                }, time)

            }
        }

    </script>
</body>

</html>

效果图:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值