irpas技术客

用JavaScript写的贪吃蛇游戏(很简单,很详细)_编程界明世隐_贪吃蛇js

irpas 5123

效果

编写外部框架 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> *{ margin: 0; padding: 0; } #box{ width:620px; height:450px; position:absolute; margin:0 auto; left:0; top:20px; right:0; bottom:0; background:gray; border-radius:10px; } #snakeDiv{ width:600px; height:400px; position:absolute; margin:0 auto; left:0; top:10px; right:0; bottom:0; } .bottom{ width:600px; height:30px; position:absolute; bottom:1px; right:1px; } .bottom .button1{ position: absolute; right: 90px; width: 50px; font-size: 14px; } .bottom .button2{ position: absolute; right: 30px; width: 50px; font-size: 14px; } .bottom .span1{ position: absolute; left: 10px; color: white; } .bottom .span2{ position: absolute; left: 200px; color: white; } </style> </head> <body> <div id='box'> <div id='snakeDiv'> </div> <div class='bottom'> <span id='score' class='span1'>分数:0</span> <span id='time' class='span2'>时间:0</span> <button onclick='start()' class='button1'>开始</button> <button onclick='stop()' class='button2'>结束</button> </div> </div> <script type="text/javascript" src='snake.js'></script> </body> </html>

效果:

添加内部画布,以及绘制地图

首先创建线的构造函数Line

function Line(ctx,o){ this.x=0,//x坐标 this.y=0,//y坐标 this.startX=0,//开始点x位置 this.startY=0, //开始点y位置 this.endX=0,//结束点x位置 this.endY=0;//结束点y位置 this.thin=false;//设置变细系数 this.ctx=ctx; this.init(o); } Line.prototype.init=function(o){ for(var key in o){ this[key]=o[key]; } } Line.prototype.render=function(){ innerRender(this); function innerRender(obj){ var ctx=obj.ctx; ctx.save() ctx.beginPath(); ctx.translate(obj.x,obj.y); if(obj.thin){ ctx.translate(0.5,0.5); } if(obj.lineWidth){//设定线宽 ctx.lineWidth=obj.lineWidth; } if(obj.strokeStyle){ ctx.strokeStyle=obj.strokeStyle; } //划线 ctx.moveTo(obj.startX, obj.startY); ctx.lineTo(obj.endX, obj.endY); ctx.stroke(); ctx.restore(); } return this; } 设定参数、执行绘制等相关方法 function SnakeProxy(el){ this.renderArr=[];//待渲染对象存储数组 this.snakeDir=4;//蛇行走方向 this.snakeArr=[];//用来存蛇头、蛇身、蛇尾的数组 this.snakePosArr=[];//存蛇头、蛇身、蛇尾分别对应的位置 this.score=0;//分数 this.time=0;//时间 this.moveCount=1;//计时控制器 } SnakeProxy.prototype.init=function(el,score,time){ if(!el) return ; this.el=el; this.scoreEL=score; this.timeEL=time; var canvas = document.createElement('canvas');//创建画布 canvas.style.cssText="background:darkgrey;border:1px solid grey;border-radius:10px;";//设置样式 var W = canvas.width = 600; //设置宽度 var H = canvas.height = 400;//设置高度 el.appendChild(canvas);//添加到指定的dom对象中 this.ctx = canvas.getContext('2d'); this.canvas=canvas; this.w=W; this.h=H; this.disX=20;//每个格子的x方向大小 this.disY=20;//每个格子的y方向大小 this.maxX=30;//x方向格子总数 this.maxY=20;//y方向格子总数 this.draw();//绘制 } SnakeProxy.prototype.createMap=function(){ var renderArr = this.renderArr; var disX = this.disX; var disY = this.disY; var maxX=this.maxX; var maxY=this.maxY; var rectW = this.w; var rectH = this.h; var rect=null; var color; for(var i=1;i<maxY;i++){//20行 var line = new Line(this.ctx,{ x:0, y:0, startX:0, startY:i*disY, endX:this.w, endY:i*disY, thin:true, strokeStyle:'white', lineWidth:0.2 }) renderArr.push(line); } for(var i=1;i<maxX;i++){//30列 var line = new Line(this.ctx,{ x:0, y:0, startX:i*disX, startY:0, endX:i*disX, endY:this.h, thin:true, strokeStyle:'white', lineWidth:0.2 }) renderArr.push(line); } } SnakeProxy.prototype.draw=function(){ this.createMap();//绘制地图 this.render();//渲染 }

此时游戏区域的格子以及绘制如下:

再来绘制蛇和食物(这里都是以圆形来做的)

创建Ball构造函数

//构造函数 function Ball(o){ this.x=0,//圆心X坐标 this.y=0,//圆心Y坐标 this.r=0,//半径 this.startAngle=0,//开始角度 this.endAngle=0,//结束角度 this.anticlockwise=false;//顺时针,逆时针方向指定 this.stroke=false;//是否描边 this.fill=false;//是否填充 this.scaleX=1;//缩放X比例 this.scaleY=1;//缩放Y比例 this.init(o); } //初始化 Ball.prototype.init=function(o){ for(var key in o){ this[key]=o[key]; } } //绘制 Ball.prototype.render=function(context){ var ctx=context; ctx.save(); ctx.beginPath(); ctx.translate(this.x,this.y); ctx.scale(this.scaleX,this.scaleY);//设定缩放 ctx.arc(0,0,this.r,this.startAngle,this.endAngle);//画圆 if(this.lineWidth){//线宽 ctx.lineWidth=this.lineWidth; } if(this.fill){//是否填充 this.fillStyle?(ctx.fillStyle=this.fillStyle):null; ctx.fill(); } if(this.stroke){//是否描边 this.strokeStyle?(ctx.strokeStyle=this.strokeStyle):null; ctx.stroke(); } ctx.restore(); return this; } 绘制蛇头 SnakeProxy.prototype.createHead=function(){ var renderArr = this.renderArr; var disX = this.disX; var disY = this.disY; var x=1,y=0; var head = new Ball({ x:x*disX+disX/2, y:y*disY+disY/2, r:disX/2-2, startAngle:0, endAngle:2*Math.PI, fill:true, fillStyle:'#F5DC10', lineWidth:1.2 }) renderArr.push(head); this.snakeArr.push(head); this.snakePosArr.push({x:x,y:y}); } 蛇身(先不绘制出来,先放代码) SnakeProxy.prototype.createBody=function(){ var renderArr = this.renderArr; var disX = this.disX; var disY = this.disY; var x=1,y=0; var body = new Ball({ x:x*disX+disX/2, y:y*disY+disY/2, r:disX/3, startAngle:0, endAngle:2*Math.PI, fill:true, fillStyle:'#F5DC10', lineWidth:1.2 }) renderArr.push(body); this.snakeArr.splice(1,0,body);//在头部后面添加 } 绘制蛇尾 SnakeProxy.prototype.createEnd=function(){ var renderArr = this.renderArr; var disX = this.disX; var disY = this.disY; var x=0,y=0; var end = new Ball({ x:x*disX+disX/2, y:y*disY+disY/2, r:disX/4, startAngle:0, endAngle:2*Math.PI, fill:true, fillStyle:'#F5DC10', lineWidth:1.2 }) renderArr.push(end); this.snakeArr.push(end); this.snakePosArr.push({x:x,y:y}); } 绘制食物(蛋) SnakeProxy.prototype.createEgg=function(){ var renderArr = this.renderArr; var disX = this.disX; var disY = this.disY; var x=_.getRandom(0,30),y=_.getRandom(0,20); var egg = new Ball({ x:x*disX+disX/2, y:y*disY+disY/2, r:disX/2-2, startAngle:0, endAngle:2*Math.PI, scaleY:0.8, fill:true, fillStyle:'#FCF6DB', lineWidth:1.2 }) renderArr.push(egg); this.egg=egg; this.eggPos={x:x,y:y}; var that=this; egg.update=function(){//update方法,蛋被吃以后,新随机出现在地图中 var x=_.getRandom(0,30),y=_.getRandom(0,20); this.x=x*disX+disX/2,this.y=y*disY+disY/2; that.eggPos={x:x,y:y}; } }

蛋加多了一个方法,用来更新位置(当被蛇吃了后)

给开始、结束按钮加入事件 var snakeDiv = document.getElementById('snakeDiv'); var score= document.getElementById('score'); var time= document.getElementById('time'); snake.init(snakeDiv,score,time); function start(){ snake.start() } function stop(){ snake.stop() } SnakeProxy.prototype.start=function(){ if(this.timmer) return ; if(this.hasEnd){//如果是结束则需要重新开始,暂停的话就继续游戏 this.restart(); } this.hasEnd=false; this.timmer = setInterval(this.move.bind(this),250);//开始定时任务 } SnakeProxy.prototype.stop=function(){ if(!this.timmer) return ; clearInterval(this.timmer);//清除定时任务 this.timmer=null; }

此时的效果如下:

加入方向控制 SnakeProxy.prototype.control=function(){ var that=this; global.addEventListener('keydown',function(e){ switch (e.keyCode){ case 38: if(that.snakeDir==1||that.snakeDir==2){ break; } that.snakeDir=1;//上 break; case 40: if(that.snakeDir==1||that.snakeDir==2){ break; } that.snakeDir=2;//下 break; case 37: if(that.snakeDir==3||that.snakeDir==4){ break; } that.snakeDir=3;//左 break; case 39: if(that.snakeDir==3||that.snakeDir==4){ break; } that.snakeDir=4;//右 break; } console.log(that.snakeDir) }); } 加入蛇的下一个坐标更新 SnakeProxy.prototype.update=function(){ var posArr = this.snakePosArr,pos; var disX=this.disX,disY=this.disY; _.each(this.snakeArr,function(s,i){ pos = posArr[i]; s.x=pos.x*disX+disX/2; s.y=pos.y*disY+disY/2; }) } SnakeProxy.prototype.computedNext=function(obj){ var x =obj.x, y = obj.y; switch (this.snakeDir){ case 1: y=obj.y-1; break; case 2: y=obj.y+1; break; case 3: x=obj.x-1; break; case 4: x=obj.x+1; break; } return {x:x,y:y} } 再加上吃食物、咬到自己、计算时间、计算分数、定时move函数就完成了 SnakeProxy.prototype.eat=function(head){ var pos = this.eggPos; if(head.x===pos.x && head.y===pos.y){//如果头部与蛋整体重合的话就吃 this.egg.update();//重新随机蛋的位置 //添加蛇的身体 this.createBody(); this.calcuScore();//计算分数 return true; } return false; } SnakeProxy.prototype.eatSelf=function(head){ var snakePosArr=this.snakePosArr; for(var i=1;i<snakePosArr.length;i++){ var s = snakePosArr[i]; if(head.x==s.x && head.y==s.y){ return true; } } return false; } SnakeProxy.prototype.end=function(head,oldHead){ if(head.x>=this.maxX || head.x<0 || head.y>=this.maxY || head.y<0 ){//超出边界结束 alert('结束了') return true; } if(this.eatSelf(oldHead)){//触碰到自己也结束 alert('结束了1') return true; } return false } SnakeProxy.prototype.calcuScore=function(){ this.score+=100; this.scoreEL.innerText='分数:'+this.score; } SnakeProxy.prototype.calcuTime=function(){ if(this.moveCount%4==0){ this.time++; this.time_flag=false; this.timeEL.innerText='时间:'+this.time; } this.moveCount++; } SnakeProxy.prototype.move=function(){ this.calcuTime(); var headPos = this.snakePosArr[0]; //执行吃动作 var eatFlag = this.eat(headPos); //计算下一个坐标 var nextPos = this.computedNext(headPos); var endFlag = this.end(nextPos,headPos); if(endFlag) { this.stop(); this.hasEnd=true; return ; } if(!eatFlag){//如果吃了食物,则不行弹出最后一个 this.snakePosArr.pop(); } this.snakePosArr.unshift(nextPos); this.update(); this.render(); }

源码获取方式: 订阅我的专栏《【javascript精彩实例】》后,可以查看专栏内所有的文章,并且联系博主免费获取你心仪的源代码,专栏的文章都是上过csdn热榜的,值得信赖,【了解一下我的专栏!】 热门专栏推荐: 【1】Java小游戏(俄罗斯方块、飞机大战、植物大战僵尸等) 【2】JavaWeb项目实战(图书管理、在线考试、宿舍管理等) 【3】JavaScript精彩实例(飞机大战、贪吃蛇、验证码等) 【4】Java小白入门200例 【5】从零学Java、趣学Java 【6】Idea从零到精通


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #贪吃蛇js