概要: 使用前端基础技术实现简易版贪吃蛇,涉及到的技术点有:html、css、javascript、jQuery
要实现的功能: ①生成蛇移动的界面,这里使用二维数组(矩阵);②画出蛇;③蛇可以自动移动,并根据键盘的上下左右改变方向;④随机生成食物(食物不在蛇的身上产生);⑤吃食物,当蛇吃到食物时,蛇身变长,并且重新生成一个食物;⑥吃到食物后速度变快;⑦蛇死亡,分为两种情况,一个是吃到自己,另一个是撞墙;⑧结束游戏并重置画面(蛇的位置)。
html部分:
<div id="mainpanel" class="mainpanel"></div>
<div id="end" class="end">游戏结束!</div>
<p>
<input id="starBtn" type="button" value="开始" />
<input id="endBtn" type="button" value="结束" />
得分:<span id="point">0</span>
</p>
.mainpanel{
border: 1px solid black;
height: 400px;
width: 800px;
margin: 0px auto;
font-size: 1px;
}
.innerbg{
height: 18px;
width: 18px;
margin: 1px;
background-color: lightgray;
float: left;
}
.snake{
background-color: goldenrod;
}
.food{
background-color: lightgreen;
}
.end{
width: 200px;
height: 100px;
border: 5px solid darkgray;
background-color: #D3D3D3;
border-radius: 10px;
position: absolute;
top: 30%;
left: 50%;
margin-left: -100px;
display: none;
text-align: center;
line-height: 100px;
}
p{
text-align: center;
}
- JS部分:
定义全局变量
//蛇横纵坐标
var snakeX = [4,5,6,7];
var snakeY = [4,4,4,4];
//初始蛇头的位置
var snakeXHead = 7;
var snakeYHead = 4;
/*
蛇头的初始朝向
37左
38上
39右
40下
*/
var direction = 39;
//食物的横纵坐标
var foodX;
var foodY;
var moveTime = 100; //蛇移动的初始速度
var score = 0; //分数
var startGame; //计时函数返回的对象名
var state = true; //判断是否生成食物
var turn = true; //判断是否继续接受键盘的输入
基础数组:
var basearr = new Array(40);
for(var i = 0;i<40;i++){
basearr[i] = new Array(20);
}
画蛇:
function drawSnake(){
for(var i = 0;i<snakeX.length;i++){
if(snakeX[i]<=39&&snakeX[i]>=0&&snakeY[i]<=19&&snakeY[i]>=0){
//判断是否超出画面
basearr[snakeX[i]][snakeY[i]].addClass("snake");
}
}
}
清除蛇:
function clearSnake(){
for(var i = 0;i<snakeX.length;i++){
basearr[snakeX[i]][snakeY[i]].removeClass("snake");
}
}
蛇移动:
①每次画蛇前,先清除原有的数组;
②根据键盘的输入判断蛇头的方向后移动;
③每次移动后用shift()函数清楚数组中的第一个元素;
④其他功能函数。eat()–>吃食物;death()–>死亡;drawSnake()–>画蛇
function snakeMove(){
clearSnake();
turn = true;
switch(direction){
case 39:snakeX.push(++snakeXHead);snakeY.push(snakeYHead);break;
case 37:snakeX.push(--snakeXHead);snakeY.push(snakeYHead);break;
case 38:snakeX.push(snakeXHead);snakeY.push(--snakeYHead);break;
case 40:snakeX.push(snakeXHead);snakeY.push(++snakeYHead);break;
}
snakeX.shift();
snakeY.shift();
eat();
death();
drawSnake();
}
食物出现:
①用random函数随机生成食物的X、Y坐标;
②遍历循环蛇身数组,判断当随机生成的食物在蛇身上时不生成食物,并继续循环直到不在为止。
function foodShow(){
do{
foodX = Math.floor(Math.random()*39+0);
foodY = Math.floor(Math.random()*19+0);
state = false;
for(var i = 0;i<snakeX.length;i++){
if(snakeX[i]==foodX&&snakeY[i]==foodY){
console.log("在蛇身上出现!不生成!")
state = true;
}
}
}while(state)
basearr[foodX][foodY].addClass("food");
console.log("食物坐标:"+foodX,foodY);
}
吃食物动作: 当蛇头的XY坐标与食物的XY坐标一致时,吃到食物(碰撞事件)。
①分数+1;
②蛇速度变快,重置计时函数的时间,而后重新调用计时函数;
③移除当前食物,再次生成食物;
④使用unshift()函数给数组的开头添加一个新的元素并返回新的长度。
function eat(){
if(snakeXHead==foodX&&snakeYHead==foodY){
score += 1;
moveTime -= 2;
clearTimeout(startGame);
startGame = setInterval(snakeMove,moveTime);
$("#point").html(score);
console.log("蛇移动速度"+moveTime);
$(".food").removeClass('food');
foodShow();
snakeX.unshift(foodX);
snakeY.unshift(foodY);
}
}
死亡:
①当蛇头的XY坐标和自身XY坐标重合时(吃到自己),调用clearInterval()函数停止计时函数,游戏结束;
②当蛇头的XY坐标超过界面长度时(撞墙),调用clearInterval()函数停止计时函数,游戏结束;
function death(){
for(var i =0;i<snakeX.length-1;i++){
if(snakeX[i] == snakeXHead && snakeY[i] == snakeYHead){
clearInterval(startGame);
$("#end").show();
console.log("吃到自己啦!")
}
if(snakeXHead>39 ||snakeXHead<0 || snakeYHead>19 || snakeYHead<0 ){
clearInterval(startGame);
$("#end").show();
console.log("出界啦!")
}
}
}
重置页面:
function initGame(){
$("#mainpanel").html("");//防止叠加界面
//重置坐标面板
for(var y = 0;y<20;y++){
for(var x = 0;x<40;x++){
var mycontent = $('');
basearr[x][y] = mycontent;
$("#mainpanel").append(basearr[x][y]);
}
}
snakeX =[4,5,6,7];
snakeY =[4,4,4,4];
drawSnake();
snakeXHead = 7;
snakeYHead = 4;
direction = 39;
turn = true;
moveTime = 100;
}
- jQuery部分:
创建画面: 40*20
for(var y = 0;y<20;y++){
for(var x = 0;x<40;x++){
var mycontent = $('');
basearr[x][y] = mycontent;
$("#mainpanel").append(basearr[x][y]);
}
}
drawSnake();//创建初始蛇
通过键盘输入改变蛇移动的方向:
①限定接受键盘输入的范围(37-40);
②Math.abs(direction-event.keyCode)!=2
用于判断不能直接掉头移动。例:当蛇头右移动时不能接收←、当蛇头向下移动时不能接收 ↑;
③turn作用:例如当蛇正在向下移动,此时快速按 → ↑,会导致蛇头穿过自己(死亡),为了防止这种情况发生,加入一个布尔变量turn,一次只接收一个按键的输入,当蛇再次移动时将turn的值变更为true;
$(document).keyup(function(event){
if(turn&&event.keyCode<=40&&event.keyCode>=37&&Math.abs(direction-event.keyCode)!=2){
direction = event.keyCode;
turn = false;
}
})
开始按钮绑定监听事件:
①禁用开始按钮,开启结束按钮;
②重置画面
③开始计时函数,生成食物
$("#starBtn").click(function(){
$(this).prop("disabled",true);
$("#endBtn").prop("disabled",false);
initGame()
$("#end").hide();
startGame = setInterval(snakeMove,moveTime);
foodShow();
})
结束按钮绑定监听事件:
①结束计时函数
②清空分数
③禁用结束按钮,开启开始按钮;
④移除画面中的食物,展示结束弹窗;
$("#endBtn").click(function(){
clearInterval(startGame);
score = 0;
$("#point").html(score);
$(this).prop("disabled",true);
$("#starBtn").prop("disabled",false);
$(".food").removeClass('food');
$("#end").show();
})
总结: 一周的前端技术学习后实现的贪吃蛇小游戏。总体思路容易理通,关键点在于处理每个动过时的逻辑需要更细致,否则运行时就会出一些bug。
难点归纳:
①为了实现蛇的动态移动,需要考虑到每次增加元素后要及时删除一个元素,才能实现动态移动。
②如何防止食物不在蛇身上出现?
首先要考虑到出现在蛇身上时的食物XY坐标是与蛇的XY数组坐标相重合的,使用do while循环并遍历蛇身数组进行判断,当重合时将while循环条件实现为true,直到不重合false跳出do while循环生成食物。
③吃食物时如何让蛇变长?
这个动作的实现方法很多,我是直接使用unshift()函数增加元素,也可以进行判断,当吃到食物时不用shift()删除元素就可以。
④怎么让蛇每次吃到食物后速度变快?
在吃到食物时,先要停止当前的计时函数,而后再次调用setInterval()函数,并将时间设为变量,每次吃到食物后做减法。