如何使用JavaScript实现贪吃蛇小游戏(javascript,web开发)

时间:2024-04-29 13:13:37 作者 : 石家庄SEO 分类 : web开发
  • TAG :

JavaScript实现贪吃蛇小游戏

功能概述

本程序实现了如下功能:

  1. 贪吃蛇的基本功能

  2. 统计得分

  3. 开始与暂停

  4. 选择难度等级

  5. 设置快捷键

    5.1 通过ijkl,wsad也能实现方向的切换

    5.2 通过“P” 表示暂停,“C”表示开始或继续,"R"表示重新开始

实现过程

最开始的实现原理其实是参考的csdn的一位大神,他用JavaScript20行就实现了贪吃蛇的基本功能,难等可贵的是还没有bug,链接在此

要实现贪吃蛇大概有以下几个步骤:

  • 画一个蛇的移动区域

  • 画一条蛇

  • 画食物

  • 让蛇动起来

  • 设定游戏规则

  • 设置难度等级

  • 设置开始与暂停

  • 设置游戏结束后续操作

  • 实现人机交互页面

注:下面的过程讲解部分只是讲述了部分原理与实现,建议一边看最后的完整代码,一边看下面的讲解,更容易理解每一部分的原理与实现

画蛇的活动区域

首先我们画蛇的活动区域,我们采用JavaScript的canvas进行绘制

我们用一个400 × 400 400\times 400400×400的区域作为蛇的活动区域

<canvasid="canvas"width="400"height="400"></canvas>

同时通过CSS设置一个边界线

#canvas{border:1pxsolid#000000;/*设置边框线*/}
画蛇和食物

效果如下:

如何使用JavaScript实现贪吃蛇小游戏

在画蛇前我们需要想下蛇的数据结构,在这里我们采取最简单的队列表示蛇

  • 队首表示蛇头位置,队尾表示蛇尾位置

  • 我们将之前画的 400 × 400 400\times 400 400×400区域划分为400个 20 × 20 20\times 20 20×20的方块,用这些方块组成蛇,那么蛇所在方块的位置的取值范围就是0~399

    举个例子:

    varsnake=[42,41,40];

    上述代码表示蛇所在的位置为42,41,40三个方块,其中蛇头为42,蛇尾为40

对于食物,我们可以用一个变量food存储食物的位置即可,食物的取值范围为0~399,且不包括蛇的部分,由于游戏中需要随机产生食物,随机函数实现如下:

//产生min~max的随机整数,用于随机产生食物的位置functionrandom(min,max){constnum=Math.floor(Math.random()*(max-min))+min;returnnum;}

当食物被蛇吃掉后就需要重新刷新食物,由于食物不能出现在蛇所在的位置,我们用一个while循环,当食物的位置不在蛇的数组中则跳出循环

while(snake.indexOf((food=random(0,400)))>=0);//重新刷新食物,注意食物应不在蛇内部

我们接下来通过canvas进行绘制

首先在js中获取canvas组件

constcanvas=document.getElementById("canvas");constctx=canvas.getContext("2d");

然后写绘制函数用于绘制方格,绘制方格的时候注意我们预留1px作为边框,即我们所画的方格的边长为18,我们实际填充的是18 × 18 18\times 1818×18的方块,方块的x、y坐标(方块的左上角)的计算也需要注意加上1px

注:canvas的原点坐标在左上角,往右为x轴正方向,往下为y轴正方向

//用于绘制蛇或者是食物代表的方块,seat为方块位置,取值为0~399,color为颜色functiondraw(seat,color){ctx.fillStyle=color;//填充颜色//fillRect的四个参数分别表示要绘制方块的x坐标,y坐标,长,宽,这里为了美观留了1px用于边框ctx.fillRect((seat%20)*20+1,Math.floor(seat/20)*20+1,18,18);}
让蛇动起来

我们要想让蛇动起来,首先要规定蛇运动的方向,我们用一个变量direction来表示蛇运动的方向,其取值范围为{1,-1,20,-20},1 表示向右,-1 表示向左,20 表示向下,-20 表示向上,运动时只需要将蛇头的位置加上direction就可以表示新蛇头的位置,这样我们就可以表示蛇的运动了。

那么如何让蛇动起来呢,对于蛇的每次移动,我们需要完成下面几个基本操作:

  1. 将蛇运动的下一个位置变成新蛇头

    • 将下一个位置加入蛇队列

    • 绘制下一个方块为浅蓝色

  2. 把旧蛇头变成蛇身

    • 绘制旧蛇头为浅灰色

  3. 删除旧蛇尾

    • 将旧蛇尾弹出蛇队列

    • 绘制旧蛇尾位置为白色

当蛇吃掉食物时(蛇的下一个位置为食物所在位置)则需更新食物的位置,并绘制新食物为黄色,此时则不需要删除旧蛇尾,这样可以实现蛇吃完食物后长度的增加功能

我们需要写一个函数实现上述操作,并且要不断地调用这个函数,从而实现页面的刷新,即我们所说的动态效果

n=snake[0]+direction;//找到新蛇头坐标snake.unshift(n);//添加新蛇头draw(n,"#1a8dcc");//绘制新蛇头为浅蓝色draw(snake[1],"#cececc");//将原来的蛇头(浅蓝色)变成蛇身(浅灰色)if(n==food){while(snake.indexOf((food=random(0,400)))>=0);//重新刷新食物,注意食物应不在蛇内部draw(food,"Yellow");//绘制食物}else{draw(snake.pop(),"White");//将原来的蛇尾绘制成白色}

接下来,我们需要实现通过键盘控制蛇的运动

我们需要获取键盘的key值,然后通过一个监听函数去监听键盘按下的操作,我们这里通过上下左右键(还拓展了WSAD键和IJKL键控制上下左右方向),同时设置一个变量n表示下一步的方向

//用于绑定键盘上下左右事件,上下左右方向键,代表上下左右方向document.onkeydown=function(event){constkeycode=event.keyCode;if(keycode<=40){//上38下40左37右39n=[-1,-20,1,20][keycode-37]||direction;//若keycode为其他值,即表示按了没用的键,则方向不变}elseif(keycode<=76&&keycode>=73){//i73j74k75l76n=[-20,-1,20,1][keycode-73]||direction;}else{switch(keycode){case87://wn=-20;break;case83://sn=20;break;case65://an=-1;break;case68://dn=1;break;default:n=direction;}}direction=snake[1]-snake[0]==n?direction:n;//若方向与原方向相反,则方向不变};
设定游戏规则

贪吃蛇的最基础的游戏规则如下:

  1. 蛇如果撞到墙或者蛇的身体或尾巴则游戏结束

  2. 蛇如果吃掉食物则蛇的长度会增加(上一步已经实现)且得分会增加

先实现第一个,具体如下:

注:下面的一段代码中的n即为新蛇头的位置

//判断蛇头是否撞到自己或者是否超出边界if(snake.indexOf(n,1)>0||n<0||n>399||(direction==1&&n%20==0)||(direction==-1&&n%20==19)){game_over();}

接下来我们实现得分统计,对于得分的计算我们只需要设置一个变量score,用于统计得分,然后每吃一个食物,该变量加一,然后将得分信息更新到网页相应位置

score=score+1;score_cal.innerText="目前得分:"+score;//更新得分
设置难度等级

我们在网页上设置一个单选框,用于设置难度等级

<formaction=""id="mode_form">难度等级:<inputtype="radio"name="mode"id="simply"value="simply"checked/><labelfor="simply">简单</label><inputtype="radio"name="mode"id="middle"value="middle"/><labelfor="middle">中级</label><inputtype="radio"name="mode"id="hard"value="hard"/><labelfor="hard">困难</label></form>

效果如下:

如何使用JavaScript实现贪吃蛇小游戏

那么我们后台具体如何设置难度等级的功能呢?

我们采取调用蛇运动的函数的时间间隔来代替难度,时间间隔越小则难度越大,我们分三级:简单、中级、困难

我们创建一个时间间隔变量time_internal,然后用一个函数获取单选框的取值,并将相应模式的时间间隔赋值给time_internal

//用刷新间隔代表蛇的速度,刷新间隔越长,则蛇的速度越慢constsimply_mode=200;constmiddle_mode=100;consthard_mode=50;vartime_internal=simply_mode;//刷新时间间隔,用于调整蛇的速度,默认为简单模式//同步难度等级functionsyncMode(){varmode_value="";for(vari=0;i<mode_item.length;i++){if(mode_item[i].checked){mode_value=mode_item[i].value;}}switch(mode_value){case"simply":time_internal=simply_mode;break;case"middle":time_internal=middle_mode;break;case"hard":time_internal=hard_mode;break;}}

最后只需要在蛇每次移动前调用一次上述函数syncMode()就可以实现难度切换,至于蛇的速度的具体调节且看下面如何讲解

设置开始与暂停

如何实现蛇的移动动态效果,如何暂停,如何继续,速度如何调节,这就涉及到JavaScript的动画的部分了,建议看下《JavaScript高级程序设计(第4版)》第18章的部分,讲的很详细。

在最初的“20行JavaScript实现贪吃蛇”中并没有实现开始与暂停,其实现动态效果的方法为设置一个立即执行函数!function() {}();,然后在该函数中使用setTimeout(arguments.callee, 150);,每隔0.15秒调用此函数,从而实现了网页的不断刷新,也就是所谓的动态效果。

后来,我通过web课程老师的案例(弹球游戏)中了解到requestAnimationFrame方法可以实现动画效果,于是我便百度查询,最后在翻书《JavaScript高级程序设计(第4版)》第18章动画与Canvas图形中得到启发–如何实现开始与取消,如何自定义时间间隔(实现难度调节,蛇的速度)

书中给出的开始动画与取消动画的方法如下:

注:为了便于理解,自己修改过原方法

varrequestID;//用于标记请求ID与取消动画functionupdateProgress(){ //dosomething...requestID=requestAnimationFrame(updateProgress);//调用后在函数中反复调用该函数}id=requestAnimationFrame(updateProgress);//第一次调用(即开始动画)cancelAnimationFrame(requestID);//取消动画

书中讲述道:

requestAnimationFrame()已经解决了浏览器不知道 JavaScript 动画何时开始的问题, 以及最佳间隔是多少的问题。······

传给 requestAnimationFrame()的函数实际上可以接收一个参数,此参数是一个 DOMHighResTimeStamp 的实例(比如 performance.now()返回的值),表示下次重绘的时间。这一点非常重要: requestAnimationFrame()实际上把重绘任务安排在了未来一个已知的时间点上,而且通过这个参数 告诉了开发者。基于这个参数,就可以更好地决定如何调优动画了。

requestAnimationFrame()返回一个请求 ID,可以用于通过另一个 方法 cancelAnimationFrame()来取消重绘任务

书中同样给出了如何控制时间间隔的方法:

书中讲述道:

配合使用一个计时器来限制重绘操作执行的频率。这样,计时器可以限制实际的操作执行间隔,而 requestAnimationFrame 控制在浏览器的哪个渲染周期中执行。下面的例子可以将回调限制为不超过 50 毫秒执行一次

具体方法如下:

letenabled=true;functionexpensiveOperation(){ console.log('Invokedat',Date.now());}window.addEventListener('scroll',()=>{if(enabled){enabled=false;requestAnimationFrame(expensiveOperation);setTimeout(()=>enabled=true,50);}});

由上面的方法我得到启发,在此处我们可以设置一个控制函数,用于控制隔一定的时间调用一次蛇运动的函数,实现如下:

//控制游戏的刷新频率,每隔time_internal时间间隔刷新一次functiongame_control(){if(enabled){enabled=false;requestAnimationFrame(run_game);setTimeout(()=>enabled=true,time_internal);}run_id=requestAnimationFrame(game_control);}//启动或继续游戏functionrun_game(){syncMode();//同步难度等级n=snake[0]+direction;//找到新蛇头坐标snake.unshift(n);//添加新蛇头//判断蛇头是否撞到自己或者是否超出边界if(snake.indexOf(n,1)>0||n<0||n>399||(direction==1&&n%20==0)||(direction==-1&&n%20==19)){game_over();}draw(n,"#1a8dcc");//绘制新蛇头为浅蓝色draw(snake[1],"#cececc");//将原来的蛇头(浅蓝色)变成蛇身(浅灰色)if(n==food){score=score+1;score_cal.innerText="目前得分:"+score;//更新得分while(snake.indexOf((food=random(0,400)))>=0);//重新刷新食物,注意食物应不在蛇内部draw(food,"Yellow");//绘制食物}else{draw(snake.pop(),"White");//将原来的蛇尾绘制成白色}//setTimeout(arguments.callee,time_internal);//之前的方案,无法实现暂停和游戏的继续}

至于暂停只需要在特定的位置调用cancelAnimationFrame(run_id);就可以了

设置游戏结束后续操作

我想的是在游戏结束后出现一个“弹窗”,显示最终得分和是否再来一把

效果如下:

如何使用JavaScript实现贪吃蛇小游戏

首先,我们实现网页的弹窗,通过调研发现JavaScript的弹窗可以通过alert()的方法实现,不过在网页上直接弹窗感觉不太美观,而且影响体验,于是我想了一下,可以采用一个p标签实现伪弹窗,在需要显示的时候设置其display属性为block,不需要显示的时候设置其display属性为none,就类似于Photoshop里面的图层概念,这样我们就可以在平常的时候设置其display属性为none触发game over时设置其display属性为block,实现如下:

<pid="game_over"><h4id="game_over_text"align="center">游戏结束!</h4><h4id="game_over_score"align="center">您的最终得分为:0分</h4><buttonid="once_again">再来一把</button><buttonid="cancel">取消</button></p>

其CSS部分如下:

#game_over{display:none;/*设置gameover窗口不可见*/position:fixed;top:190px;left:65px;width:280px;height:160px;background-color:aliceblue;border-radius:5px;border:1pxsolid#000;/*设置边框线*/}#once_again{position:relative;left:20px;}#cancel{position:relative;left:50px;}

接下来,我们需要实现game over的后续操作:暂停动画,显示得分,显示“弹窗”

functiongame_over(){cancelAnimationFrame(run_id);game_over_score.innerText="您的最终得分为:"+score+"分";game_over_p.style.display="block";}
实现人机交互页面

接下来的部分就是提高用户体验的部分,具体实现下列功能/操作

  1. 游戏说明

  2. 人机交互按钮:开始/继续,暂停,重新开始

  3. 快捷键

    • 由于在游戏过程中通过鼠标移动到暂停键暂停,时间上太慢,可能造成游戏终止,故应该设置开始/继续(C)、暂停(P)、重新开始(R)的快捷键

    • 有些电脑键盘的上下左右键较小,操作起来不太方便,可以添加WSAD或者IJKL扩展,用于控制上下左右方向

效果如下:

如何使用JavaScript实现贪吃蛇小游戏

至于写界面的代码,可以看文末的完整代码,这里就稍微讲解下绑定按键点击事件与绑定快捷键

我们首先看下绑定按键点击事件,点击”开始/继续“只需要调用requestAnimationFrame(game_control);,点击”暂停“只需要调用cancelAnimationFrame(run_id);

//绑定开始按钮点击事件start_btn.onclick=function(){run_id=requestAnimationFrame(game_control);};//绑定暂停按钮点击事件pause_btn.onclick=function(){cancelAnimationFrame(run_id);};

点击“重新开始”的话,则需要先暂停动画,然后删除画面上的蛇和食物,初始化所有设置,然后再调用requestAnimationFrame(game_control);开始游戏

注:初始化时需要初始化得分与难度等级,这里解释下为什么要将第一个食物设置为蛇头下一个位置,因为这样的话蛇会自动先吃一个食物,继而可以通过“开始 / 继续” 一个按钮实现开始和继续操作,同时run_game()函数中的食物绘制是在蛇吃到食物之后,保证第一个食物顺利绘制,这样的话score就需要初始化为-1

//用于初始化游戏各项参数functioninit_game(){snake=[41,40];direction=1;food=42;score=-1;time_internal=simply_mode;enabled=true;score_cal.innerText="目前得分:0分";//更新得分mode_item[0].checked=true;//重置难度等级为简单}//绑定重新开始按钮点击事件restart_btn.onclick=function(){cancelAnimationFrame(run_id);//将原有的食物和蛇的方块都绘制成白色for(vari=0;i<snake.length;i++){draw(snake[i],"White");}draw(food,"White");//初始化游戏各项参数init_game();run_id=requestAnimationFrame(game_control); };

接下来,我们绑定game over中的两个按键”再来一把“和”取消“

”再来一把“只需要完成“重新开始”里面的事件即可,”取消“只需要完成”重新开始“点击操作中除了开始游戏的部分,即除了run_id = requestAnimationFrame(game_control);

这两个按钮都需要设置”弹窗“的display属性为none

具体实现如下:

//绑定游戏结束时的取消按钮点击事件cancel_btn.onclick=function(){for(vari=0;i<snake.length;i++){draw(snake[i],"White");}draw(food,"White");init_game();game_over_p.style.display="none";}//绑定游戏结束时的再来一把按钮点击事件once_again_btn.onclick=function(){for(vari=0;i<snake.length;i++){draw(snake[i],"White");}draw(food,"White");init_game();game_over_p.style.display="none";run_id=requestAnimationFrame(game_control);}

最后,我们来讲解下如何设置快捷键,快捷键只需要用JavaScript模拟点击对应的按钮即可,实现如下:

//同时绑定R重启,P暂停,C继续document.onkeydown=function(event){constkeycode=event.keyCode;if(keycode==82){//R重启restart_btn.onclick();}elseif(keycode==80){//P暂停pause_btn.onclick();}elseif(keycode==67){//C继续start_btn.onclick();}};

问题、调试与解决

注: 此部分为本人在实现过程中出现的bug、调试过程以及解决方法,感兴趣的可以看看,不感兴趣的也可以跳过此部分,直接看文末的完整代码

问题1:点击暂停和开始,游戏正常开始,按P也可以实现暂停,按C则画面出现蛇所在的方格乱跳,无法正常开始,但是按C的操作中只模拟了”开始 / 继续“按钮的点击?

效果如下:

如何使用JavaScript实现贪吃蛇小游戏

调试过程:因为蛇头的位置是由direction控制的,故想到设置断点,同时监测这个变量的值的变化,发现这个值在按完P和C时被更新成很大的数,进而去找direction在哪里被更新,发现点击P或C后还需要执行下面这一行代码,而实际上是不需要的

direction=snake[1]-snake[0]==n?direction:n;//若方向与原方向相反,则方向不变

解决方法:只需要执行完对应的模拟鼠标点击相应按钮事件之后就直接return就可以了

原代码与修改后的代码如下:

document.onkeydown=function(event){constkeycode=event.keyCode;if(keycode==82){//R重启restart_btn.onclick();return;//后来加上的}elseif(keycode==80){//P暂停pause_btn.onclick();return;//后来加上的}elseif(keycode==67){//C继续start_btn.onclick();return;//后来加上的}elseif(keycode<=40){//上38下40左37右39n=[-1,-20,1,20][keycode-37]||direction;//若keycode为其他值,则方向不变}elseif(keycode<=76&&keycode>=73){//i73j74k75l76n=[-20,-1,20,1][keycode-73]||direction;}else{switch(keycode){case87://wn=-20;break;case83://sn=20;break;case65://an=-1;break;case68://dn=1;break;default:n=direction;}}direction=snake[1]-snake[0]==n?direction:n;//若方向与原方向相反,则方向不变};

问题2:调整难度等级后,蛇的速度并没有发生改变,但是通过console.log()发现确实调用了同步难度模式的函数?

调试过程:在同步难度等级的函数中设置console.log()方法,输出time_internal变量,同时设断点调试,发现time_internal变量不发生变化,mode_value变量始终为undefined,最后发现应该是值传递时的错误mode_value = mode_item.value;

解决方法:修改值传递的方法,加上索引,改为mode_value = mode_item[i].value;

原代码和修改后的代码如下:

//同步难度等级functionsyncMode(){varmode_value="";for(vari=0;i<mode_item.length;i++){if(mode_item[i].checked){mode_value=mode_item[i].value;//原来是mode_item.value}}switch(mode_value){case"simply":time_internal=simply_mode;break;case"middle":time_internal=middle_mode;break;case"hard":time_internal=hard_mode;break;}}

完整代码

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metahttp-equiv="X-UA-Compatible"content="IE=edge"/><metaname="viewport"content="width=device-width,initial-scale=1.0"/><title>贪吃蛇小游戏</title><style> button{ width:100px; height:40px; font-weight:bold; } #game_title{ margin-left:95px; } #canvas{ border:1pxsolid#000000;/*设置边框线*/ } #score{ font-weight:bold; } #mode_form{ font-weight:bold; } #game_over{ display:none;/*设置gameover窗口不可见*/ position:fixed; top:190px; left:65px; width:280px; height:160px; background-color:aliceblue; border-radius:5px; border:1pxsolid#000;/*设置边框线*/ } #once_again{ position:relative; left:20px; } #cancel{ position:relative; left:50px; }</style></head><body><h2id="game_title">贪吃蛇小游戏</h2><canvasid="canvas"width="400"height="400"></canvas> <pid="game_over"> <h4id="game_over_text"align="center">游戏结束!</h4> <h4id="game_over_score"align="center">您的最终得分为:0分</h4> <buttonid="once_again">再来一把</button> <buttonid="cancel">取消</button> </p> <br> <pid="game_info"> <p><b>游戏说明:</b></p> <p> <b>1</b>.用键盘上下左右键(或者IJKL键,或者WSAD键)控制蛇的方向,寻找吃的东西 <br><b>2</b>.每吃一口就能得到一定的积分,同时蛇的身子会越吃越长 <br><b>3</b>.不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴 <br><b>4</b>.在下方单选框中选择难度等级,点击"<b>开始/继续</b>"即开始游戏,点击"<b>暂停</b>"则暂停游戏, <br>&nbsp;&nbsp;&nbsp;&nbsp;再点击"<b>开始/继续</b>"继续游戏,点击"重新开始"则重新开始游戏 <br><b>5</b>.<b>快捷键</b>:"<b>C</b>"表示开始或继续,"<b>P</b>"表示暂停,"<b>R</b>"表示重新开始 </p> </p><pid="score">目前得分:0分</p><formaction=""id="mode_form">难度等级:<inputtype="radio"name="mode"id="simply"value="simply"checked/><labelfor="simply">简单</label><inputtype="radio"name="mode"id="middle"value="middle"/><labelfor="middle">中级</label><inputtype="radio"name="mode"id="hard"value="hard"/><labelfor="hard">困难</label></form><br/><buttonid="startButton">开始/继续</button><buttonid="pauseButton">暂停</button><buttonid="restartButton">重新开始</button><script> constcanvas=document.getElementById("canvas"); constctx=canvas.getContext("2d"); conststart_btn=document.getElementById("startButton"); constpause_btn=document.getElementById("pauseButton"); constrestart_btn=document.getElementById("restartButton"); constonce_again_btn=document.getElementById("once_again"); constcancel_btn=document.getElementById("cancel"); constgame_over_p=document.getElementById("game_over"); constgame_over_score=document.getElementById("game_over_score"); constscore_cal=document.getElementById("score"); constmode_item=document.getElementsByName("mode"); //用刷新间隔代表蛇的速度,刷新间隔越长,则蛇的速度越慢 constsimply_mode=200; constmiddle_mode=100; consthard_mode=50; //注意要改为varconst是不会修改的 varsnake=[41,40];//蛇身体队列 vardirection=1;//方向:1为向右,-1为向左,20为向下,-20为向上 varfood=42;//食物位置,取值为0~399 varn;//蛇的下一步的方向(由键盘和蛇的原方向决定) varscore=-1;//得分 vartime_internal=simply_mode;//刷新时间间隔,用于调整蛇的速度,默认为简单模式 letenabled=true;//用于控制是否刷新,实现通过一定频率刷新 letrun_id;//请求ID,用于暂停功能 //产生min~max的随机整数,用于随机产生食物的位置 functionrandom(min,max){ constnum=Math.floor(Math.random()*(max-min))+min; returnnum; } //用于绘制蛇或者是食物代表的方块,seat为方块位置,取值为0~399,color为颜色 functiondraw(seat,color){ ctx.fillStyle=color;//填充颜色 //fillRect的四个参数分别表示要绘制方块的x坐标,y坐标,长,宽,这里为了美观留了1px用于边框 ctx.fillRect( (seat%20)*20+1, Math.floor(seat/20)*20+1, 18, 18 ); } //同步难度等级 functionsyncMode(){ varmode_value=""; for(vari=0;i<mode_item.length;i++){ if(mode_item[i].checked){ mode_value=mode_item[i].value;//原来是mode_item.value } } switch(mode_value){ case"simply": time_internal=simply_mode; break; case"middle": time_internal=middle_mode; break; case"hard": time_internal=hard_mode; break; } } //用于绑定键盘上下左右事件,我设置了wsad,或者ijkl,或者上下左右方向键,代表上下左右方向 //同时绑定R重启,P暂停,C继续,注意:若是这几个键则不需要更新direction的值,操作结束后直接返回即可 document.onkeydown=function(event){ constkeycode=event.keyCode; if(keycode==82){ //R重启 restart_btn.onclick(); return; }elseif(keycode==80){ //P暂停 pause_btn.onclick(); return; }elseif(keycode==67){ //C继续 start_btn.onclick(); return; }elseif(keycode<=40){ //上38下40左37右39 n=[-1,-20,1,20][keycode-37]||direction;//若keycode为其他值,则方向不变 }elseif(keycode<=76&&keycode>=73){ //i73j74k75l76 n=[-20,-1,20,1][keycode-73]||direction; }else{ switch(keycode){ case87://w n=-20; break; case83://s n=20; break; case65://a n=-1; break; case68://d n=1; break; default: n=direction; } } direction=snake[1]-snake[0]==n?direction:n;//若方向与原方向相反,则方向不变 }; //用于初始化游戏各项参数 functioninit_game(){ snake=[41,40]; direction=1; food=42; score=-1; time_internal=simply_mode; enabled=true; score_cal.innerText="目前得分:0分";//更新得分 mode_item[0].checked=true;//重置难度等级为简单 } functiongame_over(){ cancelAnimationFrame(run_id); game_over_score.innerText="您的最终得分为:"+score+"分"; game_over_p.style.display="block"; } //启动或继续游戏 functionrun_game(){ syncMode();//同步难度等级 n=snake[0]+direction;//找到新蛇头坐标 snake.unshift(n);//添加新蛇头 //判断蛇头是否撞到自己或者是否超出边界 if( snake.indexOf(n,1)>0|| n<0|| n>399|| (direction==1&&n%20==0)|| (direction==-1&&n%20==19) ){ game_over(); } draw(n,"#1a8dcc");//绘制新蛇头为浅蓝色 draw(snake[1],"#cececc");//将原来的蛇头(浅蓝色)变成蛇身(浅灰色) if(n==food){ score=score+1; score_cal.innerText="目前得分:"+score;//更新得分 while(snake.indexOf((food=random(0,400)))>=0);//重新刷新食物,注意食物应不在蛇内部 draw(food,"Yellow");//绘制食物 }else{ draw(snake.pop(),"White");//将原来的蛇尾绘制成白色 } //setTimeout(arguments.callee,time_internal);//之前的方案,无法实现暂停和游戏的继续 } //控制游戏的刷新频率,每隔time_internal时间间隔刷新一次 functiongame_control(){ if(enabled){ enabled=false; requestAnimationFrame(run_game); setTimeout(()=>enabled=true,time_internal); } run_id=requestAnimationFrame(game_control); } //绑定开始按钮点击事件 start_btn.onclick=function(){ run_id=requestAnimationFrame(game_control); }; //绑定暂停按钮点击事件 pause_btn.onclick=function(){ cancelAnimationFrame(run_id); }; //绑定重新开始按钮点击事件 restart_btn.onclick=function(){ cancelAnimationFrame(run_id); //将原有的食物和蛇的方块都绘制成白色 for(vari=0;i<snake.length;i++){ draw(snake[i],"White"); } draw(food,"White"); //初始化游戏各项参数 init_game(); run_id=requestAnimationFrame(game_control); }; //绑定游戏结束时的取消按钮点击事件 cancel_btn.onclick=function(){ for(vari=0;i<snake.length;i++){ draw(snake[i],"White"); } draw(food,"White"); init_game(); game_over_p.style.display="none"; } //绑定游戏结束时的再来一把按钮点击事件 once_again_btn.onclick=function(){ for(vari=0;i<snake.length;i++){ draw(snake[i],"White"); } draw(food,"White"); init_game(); game_over_p.style.display="none"; run_id=requestAnimationFrame(game_control); }</script></body></html>
 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:如何使用JavaScript实现贪吃蛇小游戏的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:css中预处理器、后处理器以及选择器的示例分析下一篇:

2 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18