注意:尽量不要用谷歌浏览器运行,因为谷歌浏览器会把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.speedMirroringthis.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}//处理暂停状态时按jif (state === 2 && this.buttonColorNum === 3) {state = 0}//处理停止状态时按jif (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") //初始化ythis.playerDirection = num; //保存玩家的方向this.xTimerLog = setInterval(() => {this.xSnake += num //x加1this.addWalkList(this.xSnake, this.ySnake); //保存记录this.walkStart(); //行走}, this.speed)}} else if (axis === "y") {/* y轴运动器 */if (this.yTimerLog == null) {if (this.xTimerLog) this.initializeTimer("x") //初始化xthis.playerDirection = num; //保存玩家的方向this.yTimerLog = setInterval(() => {this.ySnake += num //y加1this.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>