贪吃蛇js实现
先把整体的框架画出来
css代码
/* 框体样式 */ html,body{ width: 100%; height: 100%; margin: 0; padding: 0; } #Frame{ top:50%; left:50%; width: 600px; height: 600px; background: white; margin-top:-300px; margin-left:-300px; position: absolute; text-align: center; border: aqua solid 1px; } #DisplayTab{ background-color: #cfcfcf; float: left; width: 500px; margin: -1px; height: 600px; border: #00FFFF 1px solid; } #DisplaySelect{ float: left; margin: -1px; width: 100px; height: 600px; border-left: lightgrey solid 1px; background-color: #aaffff; } .SnakeUnit{ float: left; border-radius: 5px; margin: 0; padding: 0; background-color: #cfcfcf; } .btn { display: inline-block; font-weight: 400; text-align: center; vertical-align: middle; cursor: pointer; background-image: none; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; border-radius: 4px; user-select: none; background-color: #424F63; border-color: #374152; color: #FFFFFF; margin: 20px; }
为了美观,可以加张好看的背景图
html代码
<body style="background-image: url(images/贪吃蛇P2.jfif);background-size: cover;"> <!-- 界面 --> <div id="Frame" > <!-- 操作台 --> <div id="DisplayTab"> </div> <!-- 操作选项 --> <div id="DisplaySelect"> <p>分数:</p> <span id="grade"></span> <br> <button class="btn" id="reopen">重开</button> <button class="btn" id="stop">暂停</button> <button class="btn" id="continue">继续</button> <a href="index.html"><button class="btn">首页</button></a> </div> </div>
具体实现
先给出所有的全局变量
//全局变量 var Unit_Row = 60;//行数 var Unit_list = 50;//列数 var UnitNumber = Unit_Row*Unit_list;//总单元数 var grade = 0;//分数 var vector = 1;//记录小蛇移动方向【1】左【2】上【3】下【4】右 var speed = 120;//记录速度设置,单位毫秒 var Bean = new Array(5); var Head_Loca = 0;//记录小蛇的头部位置 var Snake_path = new Array();//记录小蛇身体位置 var Snake_Add = 0;//是否允许小蛇增加 var displaytab = document.getElementById("DisplayTab"); var thread = null;//记录线程id var UnitList = new Array(UnitNumber); //单元列表
要实现小蛇移动吃食物,可以自己勾勒出像素,就是很多个div,可以用js代码实现,画出单元格。(单元格的样式css实现就行了,这里只需要加上类名。)
//画出单元格 for(let i = 0; i < UnitNumber; i++){ var unit = document.createElement("div"); unit.className = "SnakeUnit"; unit.style.width = 500/Unit_list + "px"; unit.style.height = 600/Unit_Row + "px"; displaytab.appendChild(unit); }
每个单元格都要存储信息,是否为食物,是小蛇身体还是头部。。。
//单元信息存储 function unitmessage(food,Type) { this.food = food;//是否属于食物 this.Type = Type;//【0】不属于【1】头部【2】身体 } for (let i=0;i<UnitNumber;i++) { UnitList[i] = new unitmessage(false,0); }
要想开始游戏就要有游戏帧(控制按键)和渲染帧(控制画面)。
//游戏帧 function Game_Refresh(){ switch(vector){ case 1 : console.log("←"); if(Head_Loca%Unit_list === 0){ Head_Loca += (Unit_list-1); }else{ Head_Loca -= 1; } break; case 2 : console.log("→"); if((Head_Loca-(Unit_list-1))%Unit_list === 0){ Head_Loca -= (Unit_list-1); }else{ Head_Loca += 1; } break; case 3 : console.log("↑"); if(Unit_list/Head_Loca > 1){ Head_Loca += Unit_list*(Unit_Row-1); }else{ Head_Loca -= Unit_list; } break; case 4 : console.log("↓"); if (Head_Loca/Unit_list>=(Unit_Row-1)) { Head_Loca -= Unit_list*(Unit_Row-1); } else{ Head_Loca += Unit_list; } break; default : console.log("无效输入"); return; } //游戏失败 if(Snake_path.indexOf(Head_Loca)!==-1){ alert("游戏失败"); remake(); } for(let i = 0; i < Bean.length; i++){ if(Head_Loca === Bean[i]){//吃到豆子,体型增长 Snake_Add += 1; grade += 1; //记录分数 speed -= 2; //速度加快 UnitList[Head_Loca].food = false; Bean[i] = Math.floor(Math.random()*UnitNumber); while(Snake_path.indexOf(Bean[i])!==-1){ Bean[i] = Math.floor(Math.random()*UnitNumber); } //放置豆子 UnitList[Bean[i]].food = true; } } // console.log("当前 :" + Snake_path + "head" + Head_Loca); //往最后面加一个元素(增加头部元素) Snake_path.push(Head_Loca); // console.log("当前 :" + Snake_path + "head" + Head_Loca); // 初始化身体属性 for(let loca of Snake_path){ UnitList[loca].Type = 2; } if(Snake_Add === 0){ //删除尾部元素 let Delet = Snake_path.shift(); UnitList[Delet].Type = 0; }else{ Snake_Add--; } UnitList[Head_Loca].Type = 1; } //渲染帧 function Draw_Refresh(){ //获取所有单元 let DisplayUnit = document.querySelectorAll(".SnakeUnit"); for (let i=0;i<UnitNumber;i++) { if(UnitList[i].Type === 2){ DisplayUnit[i].style.backgroundColor = "green"; }else if(UnitList[i].Type === 1){ DisplayUnit[i].style.backgroundColor = "red"; }else if(UnitList[i].food){ DisplayUnit[i].style.backgroundColor = "yellow"; }else{ DisplayUnit[i].style.backgroundColor = "#cfcfcf"; } } } document.onkeydown = function(event){ var event = event || window.event; //键盘输入 switch(event.keyCode){ case 37 : console.log("←"); if(vector!==2){ vector = 1; } break; case 39 : console.log("→"); if(vector!==1){ vector = 2; } break; case 38 : console.log("↑"); if(vector!==4){ vector = 3; } break; case 40 : console.log("↓"); if(vector!==3){ vector = 4; } break; default : console.log("无效输入"); return; } }
要有蛇的食物,必然不能少了食物生成函数。
//豆子产生 function RankBean(){ for(let i = 0; i < Bean.length; i++){ Bean[i] = Math.floor(Math.random()*UnitNumber); while(Snake_path.indexOf(Bean[i])!==-1){ Bean[i] = Math.floor(Math.random()*UnitNumber); } //放置豆子 UnitList[Bean[i]].food = true; } }
最后就是游戏的重置函数了,蛇的循环移动和速度可以用定时器解决。
//游戏重置函数 function remake(){ window.clearInterval(thread); //初始化界面信息 vector = 1; grade = 0; Head_Loca = 0; Snake_Add = 0; Snake_path = new Array(); UnitList = new Array(UnitNumber); for (let i=0;i<UnitNumber;i++) { UnitList[i] = new unitmessage(false,0); } //设置初始位置并保存 UnitList[0].Type = 1; UnitList[1].Type = 2; UnitList[2].Type = 2; UnitList[3].Type = 2; UnitList[4].Type = 2; Snake_path.push(4,3,2,1,0); RankBean(); Draw_Refresh(); // 启动线程 beginThread(); } function beginThread(){ thread = setInterval(function(){ Game_Refresh(); var element = document.getElementById("grade"); element.innerHTML = grade; Draw_Refresh(); },speed); }
在文章结尾,附上贪吃蛇的源代码(背景图可以自己换)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> /* 框体样式 */ html,body{ width: 100%; height: 100%; margin: 0; padding: 0; } #Frame{ top:50%; left:50%; width: 600px; height: 600px; background: white; margin-top:-300px; margin-left:-300px; position: absolute; text-align: center; border: aqua solid 1px; } #DisplayTab{ background-color: #cfcfcf; float: left; width: 500px; margin: -1px; height: 600px; border: #00FFFF 1px solid; } #DisplaySelect{ float: left; margin: -1px; width: 100px; height: 600px; border-left: lightgrey solid 1px; background-color: #aaffff; } .SnakeUnit{ float: left; border-radius: 5px; margin: 0; padding: 0; background-color: #cfcfcf; } .btn { display: inline-block; font-weight: 400; text-align: center; vertical-align: middle; cursor: pointer; background-image: none; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; border-radius: 4px; user-select: none; background-color: #424F63; border-color: #374152; color: #FFFFFF; margin: 20px; } </style> </head> <body style="background-image: url(images/贪吃蛇P2.jfif);background-size: cover;"> <!-- 界面 --> <div id="Frame" > <!-- 操作台 --> <div id="DisplayTab"> </div> <!-- 操作选项 --> <div id="DisplaySelect"> <p>分数:</p> <span id="grade"></span> <br> <button class="btn" id="reopen">重开</button> <button class="btn" id="stop">暂停</button> <button class="btn" id="continue">继续</button> <a href="index.html"><button class="btn">首页</button></a> </div> </div> </body> <script type="text/javascript"> //全局变量 var Unit_Row = 60;//行数 var Unit_list = 50;//列数 var UnitNumber = Unit_Row*Unit_list;//总单元数 var grade = 0;//分数 var vector = 1;//记录小蛇移动方向【1】左【2】上【3】下【4】右 var speed = 120;//记录速度设置,单位毫秒 var Bean = new Array(5); var Head_Loca = 0;//记录小蛇的头部位置 var Snake_path = new Array();//记录小蛇身体位置 var Snake_Add = 0;//是否允许小蛇增加 var displaytab = document.getElementById("DisplayTab"); var thread = null;//记录线程id var UnitList = new Array(UnitNumber); //单元列表 //画出单元格 for(let i = 0; i < UnitNumber; i++){ var unit = document.createElement("div"); unit.className = "SnakeUnit"; unit.style.width = 500/Unit_list + "px"; unit.style.height = 600/Unit_Row + "px"; displaytab.appendChild(unit); } //单元信息存储 function unitmessage(food,Type) { this.food = food;//是否属于食物 this.Type = Type;//【0】不属于【1】头部【2】身体 } for (let i=0;i<UnitNumber;i++) { UnitList[i] = new unitmessage(false,0); } // 使用重置函数初始化游戏 remake(); //游戏帧 function Game_Refresh(){ switch(vector){ case 1 : console.log("←"); if(Head_Loca%Unit_list === 0){ Head_Loca += (Unit_list-1); }else{ Head_Loca -= 1; } break; case 2 : console.log("→"); if((Head_Loca-(Unit_list-1))%Unit_list === 0){ Head_Loca -= (Unit_list-1); }else{ Head_Loca += 1; } break; case 3 : console.log("↑"); if(Unit_list/Head_Loca > 1){ Head_Loca += Unit_list*(Unit_Row-1); }else{ Head_Loca -= Unit_list; } break; case 4 : console.log("↓"); if (Head_Loca/Unit_list>=(Unit_Row-1)) { Head_Loca -= Unit_list*(Unit_Row-1); } else{ Head_Loca += Unit_list; } break; default : console.log("无效输入"); return; } //游戏失败 if(Snake_path.indexOf(Head_Loca)!==-1){ alert("游戏失败"); remake(); } for(let i = 0; i < Bean.length; i++){ if(Head_Loca === Bean[i]){//吃到豆子,体型增长 Snake_Add += 1; grade += 1; //记录分数 speed -= 2; //速度加快 UnitList[Head_Loca].food = false; Bean[i] = Math.floor(Math.random()*UnitNumber); while(Snake_path.indexOf(Bean[i])!==-1){ Bean[i] = Math.floor(Math.random()*UnitNumber); } //放置豆子 UnitList[Bean[i]].food = true; } } // console.log("当前 :" + Snake_path + "head" + Head_Loca); //往最后面加一个元素(增加头部元素) Snake_path.push(Head_Loca); // console.log("当前 :" + Snake_path + "head" + Head_Loca); // 初始化身体属性 for(let loca of Snake_path){ UnitList[loca].Type = 2; } if(Snake_Add === 0){ //删除尾部元素 let Delet = Snake_path.shift(); UnitList[Delet].Type = 0; }else{ Snake_Add--; } UnitList[Head_Loca].Type = 1; } //渲染帧 function Draw_Refresh(){ //获取所有单元 let DisplayUnit = document.querySelectorAll(".SnakeUnit"); for (let i=0;i<UnitNumber;i++) { if(UnitList[i].Type === 2){ DisplayUnit[i].style.backgroundColor = "green"; }else if(UnitList[i].Type === 1){ DisplayUnit[i].style.backgroundColor = "red"; }else if(UnitList[i].food){ DisplayUnit[i].style.backgroundColor = "yellow"; }else{ DisplayUnit[i].style.backgroundColor = "#cfcfcf"; } } } document.onkeydown = function(event){ var event = event || window.event; //键盘输入 switch(event.keyCode){ case 37 : console.log("←"); if(vector!==2){ vector = 1; } break; case 39 : console.log("→"); if(vector!==1){ vector = 2; } break; case 38 : console.log("↑"); if(vector!==4){ vector = 3; } break; case 40 : console.log("↓"); if(vector!==3){ vector = 4; } break; default : console.log("无效输入"); return; } } //豆子产生 function RankBean(){ for(let i = 0; i < Bean.length; i++){ Bean[i] = Math.floor(Math.random()*UnitNumber); while(Snake_path.indexOf(Bean[i])!==-1){ Bean[i] = Math.floor(Math.random()*UnitNumber); } //放置豆子 UnitList[Bean[i]].food = true; } } //游戏重置函数 function remake(){ window.clearInterval(thread); //初始化界面信息 vector = 1; grade = 0; Head_Loca = 0; Snake_Add = 0; Snake_path = new Array(); UnitList = new Array(UnitNumber); for (let i=0;i<UnitNumber;i++) { UnitList[i] = new unitmessage(false,0); } //设置初始位置并保存 UnitList[0].Type = 1; UnitList[1].Type = 2; UnitList[2].Type = 2; UnitList[3].Type = 2; UnitList[4].Type = 2; Snake_path.push(4,3,2,1,0); RankBean(); Draw_Refresh(); // 启动线程 beginThread(); } function beginThread(){ thread = setInterval(function(){ Game_Refresh(); var element = document.getElementById("grade"); element.innerHTML = grade; Draw_Refresh(); },speed); } var stopBtn = document.getElementById("stop"); var continueBtn = document.getElementById("continue"); var reopenBtn = document.getElementById("reopen"); stopBtn.onclick = function(){ clearInterval(thread); } continueBtn.onclick = function(){ beginThread(); } reopenBtn.onclick = function () { remake(); } </script> </html>
配图
如果有想了解具体实现的,或有不清楚明白的,可以留下评论。