注意:尽量不要用谷歌浏览器运行,因为谷歌浏览器会把GameValue翻译成中文,使游戏掉帧卡顿

解决办法:1.使用Edge浏览器,2.把谷歌浏览器的自动中文翻译关闭即可

游戏截图:

源码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" content="width=device-width,initial-scale=1.0,user-scalable=0" name="viewport">
    <title>贪吃蛇</title>

    <link href="https://llh317.oss-cn-guangzhou.aliyuncs.com/bootstrap-4.6.1-dist/bootstrap-4.6.1-dist/css/bootstrap.min.css"
          rel="stylesheet">
    <script src="https://llh317.oss-cn-guangzhou.aliyuncs.com/js-package/js/vue.js"></script>

    <style>
        * {
            user-select: none;
        }

        .mapParent {
            height: 500px;
        }

        .map {
            border: 1px red dashed;
            height: 100%;
            width: 100%;
        }

        .titleAlert {
            font-weight: bold;
        }

        .system {
            color: #909399;
            font-size: 12px;
        }

        .titleValue {
            font-size: 12px;
            color: #909399;
            margin: -10px 0;
        }

        .foot {
            text-align: center;
        }

        .butWASD button {
            font-size: 50px;
            width: 150px;
            height: 150px;
        }

        .hereto {
            color: #909399;
            margin: 0 5px;
            text-decoration: underline;
        }

        .description {
            font-size: 16px;
            color: #909399;
        }

        .footNote {
            font-size: 12px;
            color: #909399;
        }

        .sbody {
            background-color: skyblue;
        }

        .shead {
            background-color: red;
        }

        .food {
            background-color: blueviolet;
        }
    </style>
</head>

<body>
<div class="llh">
    <br>
    <br>
    <div @keydown.65="aKey"
         @keydown.68="dKey"
         @keydown.75="accelerate(true)"
         @keydown.83="sKey"
         @keydown.87="wKey"
         @keydown.down="sKey"
         @keydown.left="aKey"
         @keydown.right="dKey"
         @keydown.up="wKey"
         @keyup.74="gameState(2)"
         @keyup.75="accelerate(false)"
         class="container" id="v1">
        <div class="row">
            <div class="col-sm-3" style="text-align: center;">
                <button :class="{
                        btn:true,
                        'btn-info':buttonColorNum===0,
                        'btn-success':buttonColorNum===1,
                        'btn-danger':buttonColorNum===2,
                        'btn-warning':buttonColorNum===3
                        }" @blur="gameState(1)" @click="gameState(0)">{{buttonPrompt}}
                </button>
                <br><br>
                <h3 style="color: #303133;">得分:{{score}}</h3>
                <h6 class="titleAlert" id="open" style="color: blue;display: none;">[ 已启动加速 ]</h6>
                <h6 class="titleAlert" id="close" style="color: red;">[ 已关闭加速 ]</h6>
            </div>
            <div class="col-sm-6 mapParent">
                <table align="center" class="map" v-html="gameMapData"></table>
            </div>
            <div class="col-sm-3 system">
                <label class="titleValue">游戏参数调试板:</label>
                <br>
                <label class="titleValue">score:~~~</label>{{score}}
                <br>
                <label class="titleValue">snakeLength:~~~</label>{{snakeLength}}
                <br>
                <label class="titleValue">xSnake:~~~</label>{{xSnake}}
                <br>
                <label class="titleValue">ySnake:~~~</label>{{ySnake}}
                <br>
                <label class="titleValue">xTimerLog:~~~</label>{{xTimerLog}}
                <br>
                <label class="titleValue">yTimerLog:~~~</label>{{yTimerLog}}
                <br>
                <label class="titleValue">playerDirection:~~~</label>{{playerDirection}}
                <br>
                <label class="titleValue">X-Y:</label>{{walkList}}
            </div>
        </div>
        <br>
        <div>
            <div class="foot">
                <div class="butWASD" v-if="butWASD">
                    <button @click="wKey" class="btn btn-danger">上</button>
                    <br>
                    <button @click="aKey" class="btn btn-danger">左</button>
                    <button class="btn"></button>
                    <button @click="dKey" class="btn btn-danger">右</button>
                    <br>
                    <button @click="sKey" class="btn btn-danger">下</button>
                </div>
                <hr>
                <div class="description">
                    操作:( W-A-S-D:方向 )-(暂停/开始游戏:j )-( 加速:k )-(如果游戏出现停止运行,重新点击按钮即可)
                </div>
                <hr>
                <div class="footNote">
                    Creation time 2021-10-01
                    <a class="hereto" href="https://blog.csdn.net/L0317">©廖利辉</a>
                    <a class="hereto"
                       href="https://blog.csdn.net/L0317/article/details/122098926?spm=1001.2014.3001.5501">®TCS</a>
                    <a class="hereto" href="https://cn.vuejs.org/index.html">™VUE.JS-version:2.0</a>
                </div>
            </div>
        </div>
        <br>
    </div>
</div>
</body>
<script>
    new Vue({
        el: "#v1",
        data: {
            /* 按钮样式 */
            buttonColorNum: -1, //按钮颜色
            buttonPrompt: "", //按钮提示

            /* 绘制地图 */
            gameMapData: "", //地图的html数据
            dituSize: 100, //地图的大小

            /* 游戏参数(管远缘量身定做) */
            speed: 70, //速度
            speedMirroring: 0, //速度镜像
            score: 0, //得分
            snakeLength: 10, //蛇身长度

            /* 游戏日志 */
            walkList: [], //行走记录
            xSnake: 0, //横向
            ySnake: 0, //纵向

            xFood: 0, //食物横向
            yFood: 0, //食物纵向

            playerDirection: 0, //保存方向

            /* 计时器 */
            xTimerLog: null, //横向计时器
            yTimerLog: null, //纵向计时器

            /* 手机端按钮 */
            butWASD: false
        },
        methods: {
            accelerate(bool) {
                //加速
                this.speed = bool ? 20 : this.speedMirroring
                this.getllh("open").style.display = bool ? "block" : "none"
                this.getllh("close").style.display = bool ? "none" : "block"
            },
            gameState(state) {
                //0运行 1游戏意外停止(游戏指针转移) 2暂停

                //处理重复手动点击
                if (state === 0 && this.buttonColorNum === 1) {
                    state = 2
                }
                //处理暂停状态时按j
                if (state === 2 && this.buttonColorNum === 3) {
                    state = 0
                }
                //处理停止状态时按j
                if (state === 2 && this.buttonColorNum === 2) {
                    state = 0
                }
                if (state === 0) {
                    /* 游戏开始 */
                    this.buttonPrompt = "游戏正在运行";
                    this.buttonColorNum = 1
                    /* 初始化 */
                    if (this.xSnake === 0 && this.xFood === 0) {
                        //保持从中间出来
                        this.ySnake = this.xSnake = Math.floor(this.dituSize / 2);
                        this.setFood(); //随机产生豆子
                    } else {
                        //启动后,重新启动保持方向
                        if (this.xTimerLog != null && this.playerDirection > 0) {
                            this.xTimerLog = null; //设置为空,方向改变器
                            this.dKey();
                        } else if (this.xTimerLog != null && this.playerDirection < 0) {
                            this.xTimerLog = null; //设置为空,方向改变器
                            this.aKey();
                        } else if (this.yTimerLog != null && this.playerDirection > 0) {
                            this.yTimerLog = null; //设置为空,方向改变器
                            this.sKey();
                        } else if (this.yTimerLog != null && this.playerDirection < 0) {
                            this.yTimerLog = null; //设置为空,方向改变器
                            this.wKey();
                        }
                    }
                } else if (state === 1) {
                    // PC端需要聚焦到开始按钮,手机端不需要
                    if (!this.butWASD) {
                        /* 游戏停止 */
                        this.buttonPrompt = "游戏停止运行(继续运行)";
                        this.buttonColorNum = 2;

                        // 清空计时器
                        this.xTimerLog != null ? clearInterval(this.xTimerLog) : ""
                        this.yTimerLog != null ? clearInterval(this.yTimerLog) : ""
                    }
                } else if (state === 2) {
                    /* 游戏暂停 */
                    this.buttonPrompt = "游戏暂停运行(开始游戏)";
                    this.buttonColorNum = 3;

                    //清空计时器
                    this.xTimerLog != null ? clearInterval(this.xTimerLog) : ""
                    this.yTimerLog != null ? clearInterval(this.yTimerLog) : ""
                }
            },
            wKey() {
                this.direction("y", -1); //y轴减少
            },
            aKey() {
                this.direction("x", -1); //x轴减少
            },
            sKey() {
                this.direction("y", 1); //y轴增多
            },
            dKey() {
                this.direction("x", 1); //x轴增多
            },
            direction(axis, num) {
                /* 方向改变器 */
                //游戏必须处于运行状态
                if (this.buttonColorNum === 1) {
                    if (axis === "x") {
                        /* x轴运动器 */
                        //x轴计时器必须为空
                        if (this.xTimerLog == null) {
                            if (this.yTimerLog != null) this.initializeTimer("y") //初始化y
                            this.playerDirection = num; //保存玩家的方向
                            this.xTimerLog = setInterval(() => {
                                this.xSnake += num //x加1
                                this.addWalkList(this.xSnake, this.ySnake); //保存记录
                                this.walkStart(); //行走
                            }, this.speed)
                        }
                    } else if (axis === "y") {
                        /* y轴运动器 */
                        if (this.yTimerLog == null) {
                            if (this.xTimerLog) this.initializeTimer("x") //初始化x
                            this.playerDirection = num; //保存玩家的方向
                            this.yTimerLog = setInterval(() => {
                                this.ySnake += num //y加1
                                this.addWalkList(this.xSnake, this.ySnake); //保存记录
                                this.walkStart(); //行走
                            }, this.speed)
                        }
                    }
                }
            },
            addWalkList(x, y) {
                /* 记录保存器 */
                function Log(xLog, yLog) { //日志对象
                    this.xLog = xLog;
                    this.yLog = yLog;
                }

                this.walkList[this.walkList.length] = new Log(x, y); //当前记录添加进去

                /* 性能优化(数组长度根据蛇的长度+1去定制) +1是为了获取被清空的那个一格*/
                let performance = [];
                if (this.walkList.length > this.snakeLength) {
                    /* 截取蛇身长度的数值优化 */
                    for (let i = this.walkList.length - 1 - this.snakeLength; i <= this.walkList.length -
                    1; i++) {
                        performance[performance.length] = this.walkList[i];
                    }
                    this.walkList = performance;
                }
            },
            walkStart() {
                /* 行走器 */
                let headObj = this.walkList[this.walkList.length - 1]; //读取玩家头记录
                this.sStyle(headObj.xLog, headObj.yLog, true, "shead"); //设置头

                let bodyObj = this.walkList[this.walkList.length - 2]; //读取玩家身体记录
                if (bodyObj != null) this.sStyle(bodyObj.xLog, bodyObj.yLog, true, "sbody") //设置身体

                let clearObj = this.walkList[this.walkList.length - 1 - this.snakeLength]; //读取清空的记录
                if (clearObj != null) this.sStyle(clearObj.xLog, clearObj.yLog, false) //清空身体

                if (headObj.xLog === this.xFood && headObj.yLog === this.yFood) { //判断头部,是否触碰了食物
                    this.score += 1; //加一分
                    if (this.score % 2 === 0) this.snakeLength += 1 //2个豆子一格身子
                    this.setFood(); //随机产生食物
                }

                for (let i = 0; i <= this.walkList.length - 2; i++) { //遍历身体,判断头部是否触碰到身体
                    if (this.walkList[i].xLog === headObj.xLog && this.walkList[i].yLog === headObj.yLog) {
                        location.reload()
                        alert("游戏结束")
                    }
                }
            },
            setFood() {
                /* 食物放置器 */
                this.xFood = Math.floor(Math.random() * this.dituSize); //食物的x轴
                this.yFood = Math.floor(Math.random() * this.dituSize); //食物的y轴
                this.sStyle(this.xFood, this.yFood, true, "food"); //给食物添加样式
            },
            initializeTimer(axis) {
                /* 计时初始化器 */
                if (axis === "x") {
                    if (this.xTimerLog != null) {
                        clearInterval(this.xTimerLog)
                        this.xTimerLog = null;
                    }
                } else if (axis === "y") {
                    if (this.yTimerLog != null) {
                        clearInterval(this.yTimerLog)
                        this.yTimerLog = null;
                    }
                }
            },
            sStyle(x, y, bool, className) {
                /* 样式改变器*/
                try {
                    if (bool) {
                        /* 设置样式 */
                        this.getllh("llh-" + x + "-" + y).className = className;
                    } else {
                        /* 清空样式 */
                        this.getllh("llh-" + x + "-" + y).className = "";
                    }
                } catch (exception) {
                    location.reload()
                    alert("游戏结束")
                }
            },
            getllh(name) {
                /* 元素获取器 */
                return document.getElementById(name);
            },
            isPC() {
                // 是否为PC端
                let sUserAgent = navigator.userAgent.toLowerCase();
                return !/ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(sUserAgent);
            }
        },
        created() {
            /* 初始化地图 */

            console.log(
                `%c 贪吃蛇 %c 作者:廖利辉 %c `,
                'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px;  color: #fff',
                'background:#41b883 ; padding: 1px; border-radius: 0 3px 3px 0;  color: #fff',
                'background:transparent'
            )

            this.buttonPrompt = "地图渲染中"; // 改变按钮文字

            let size = this.dituSize; // 获取地图的参数

            /* 循环y轴 */
            for (let y = 0; y < size; y++) {
                this.gameMapData += "<tr>";
                /* 循环x轴 */
                for (let x = 0; x < size; x++) {
                    this.gameMapData += "<td id='llh-" + x + "-" + y + "'></td>";
                }
                this.gameMapData += "</tr>";
            }

            this.buttonPrompt = "地图渲染完成(开始游戏)"; // 改变按钮文字
            this.buttonColorNum = 0; // 改变按钮颜色

            this.speedMirroring = this.speed; // 将速度镜像赋值

            /* 为了展示手机端的上下左右按钮,PC不展示 */
            this.butWASD = !this.isPC() // 赋值是否为PC
        }
    })

</script>
</html>

Logo

前往低代码交流专区

更多推荐