怎么用JavaScript做俄罗斯方块游戏
这篇文章主要为大家展示了"怎么用JavaScript做俄罗斯方块游戏",内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下"怎么用JavaScript做俄罗斯方块游戏"这篇文章吧。
最终游戏效果
一开始我们先搭个框架,以便后期使用
编写外部框架
分数:0 时间:0
框架效果如下:
添加内部画布,以及绘制地图
首先创建线的构造函数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 Game(el){ this.renderArr=[];//待渲染对象存储数组 this.aliveModel=[];//用来存到底的model组合 this.score=0;//分数 this.time=0;//时间 this.moveCount=1;//计时控制器 } Game.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;";//设置样式 var W = canvas.width = 300; //设置宽度 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=15;//x方向格子总数 this.maxY=20;//y方向格子总数 this.control();// this.draw();//绘制 } //绘制地图 Game.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此时游戏区域的格子以及绘制如下:
再来绘制模型
模型定义:分别是一字形、田字形、二字形2种、七字形2种、凸字形等共7种。
变形定义:1字形可以变形2种、田字形不能变形,其他的都可以变形4种。
模型的组成:模型是有4个小方块来组成,每个模型里面有数组blocks来存取4个小方块的x、y坐标,然后绘制出来就是模型了。
模型的变形:变形的时候就只要切换每个方块的X\Y坐标就可以达到变形的效果。
下面来创建模型的构造函数
//模型构造函数 function Model(o){ this.blocks=[],//存储方块的数组,绘制的时候根据数组来绘制 this.type=1,//模型的形状,默认是一字形(共7种) this.dir=1,//方向默认为1,总共4种,其中一字形为2种,田字形为1种,其他为4种 this.x=0,//x坐标(只传入第一个x,根据这个x来生成其他的x) this.y=0,//y坐标(只传入第一个y,根据这个y来生成其他的y) this.init(o); } //初始化 Model.prototype.init=function(o){ for(var key in o){ this[key]=o[key]; } }
举例
添加一个创建七字形的方法(因为七字形有4种摆放方式,所以有dir来区分,怎么摆放)
//创建七字形1 Model.prototype.createQi1=function(){ var blocks=this.blocks,x=this.x,y=this.y; switch(this.dir){ case 1:// blocks.push({x:x,y:y}); blocks.push({x:x,y:y-1}); blocks.push({x:x,y:y-2}); blocks.push({x:x+1,y:y-2}); break; case 2:// blocks.push({x:x+2,y:y}); blocks.push({x:x+1,y:y}); blocks.push({x:x,y:y}); blocks.push({x:x,y:y-1}); break; case 3:// blocks.push({x:x+1,y:y-2}); blocks.push({x:x+1,y:y-1}); blocks.push({x:x+1,y:y}); blocks.push({x:x,y:y}); break; case 4:// blocks.push({x:x-2,y:y-1}); blocks.push({x:x-1,y:y-1}); blocks.push({x:x,y:y-1}); blocks.push({x:x,y:y}); break; } }
创建一个七字形试试(传入的x、y是第一个放个的位置)
var model = new Model({//创建1字 x:6,y:6,fillStyle:'#0370BD',fill:true,game:this,type:5,dir:1});this.renderArr.push(model);//当前的模型this.currentModel=model;
编写变形方法(每一次变形都是按前一个模样逆时针旋转90度,修改每个小方块x、y来修改就行)
------------------------ >>>
左边这个图形要变成右边的图形,需要怎么变更呢?
-------------------->>>
标上号码就很容易明白,1还是对应的1,2还是对应的2,以此类推,只不过X\Y变了
1方块:只要x+2就可以移到指定的位置;
2方块:x、y都需要加1
3方块:y+2就可以
4方块:x-1和y+1即可
其他都是一样的道理,来写一下变形的方法
//七1变形 Model.prototype.transformQi1=function(){ var blocks = this.blocks,block2=blocks[1]; switch(this.dir){ case 1://竖着的 tran1(); this.dir=2; break; case 2://横着的 tran2(); this.dir=3; break; case 3://竖着的 tran3(); this.dir=4; break; case 4://横着的 tran4(); this.dir=1; break; } function tran1(){//变成横着的 for(var i=0;i给 w 和向上键添加为变形事件,同时左移动、右移动、下加速也添加好事件
//按键的控制 Game.prototype.control=function(){ var that=this; global.addEventListener('keydown',function(e){ //if(!that.timmer) return ; switch (e.keyCode){ case 87://w case 38://上 that.currentModel.transform();//变形 break; case 83://s case 40://下 that.currentModel.move('d');//移动 break; case 65://a case 37://左 that.currentModel.move('l');//移动 break; case 68://d case 39://右 that.currentModel.move('r');//移动 break; } //测试用,记得删除 that.render(); }); }
接下来变形试试
添加移动方法
//移动 Model.prototype.move=function(dir){ var cur = this.game.currentModel,dis=1,blocks = this.blocks; if(dir=='r'||dir=='ld'){ dis=1 }else if(dir=='l'){ dis=-1; }else if(dir=='d'){ dis=3; } var stopMoveObj = this.stopMove(dir,dis), val=stopMoveObj.val,resDis=stopMoveObj.resDis; if(val) { if(dir=='d'||dir=='ld'){//到底了 [].push.apply(this.game.aliveModel,cur.blocks);//放到已到底的组合中 this.game.renderArr.pop();//当前模型弹出 this.game.clearBlock();//消除 this.game.createModel();//绘制一个新图形 } return ;//如果返回true 则不能再往这个方向移动 } if(resDis>0){ dis=resDis; } //更新每一个block的位置 for(var i=0;i加入边界判断和碰撞检测(边界检测比较简单、碰撞检测在快进的时候要注意处理一下,看代码吧)
//停止移动 Model.prototype.stopMove=function(dir,dis){ var cur = this.game.currentModel,blocks = this.blocks; var maxX = this.game.maxX,maxY = this.game.maxY,res,temp; for(var i=0;i=maxY-1){//到底了 return {val:true}; } }else if(dir=='r'){ if(block.x>=maxX-1){//到右边界了 return {val:true}; } }else if(dir=='l'){ if(block.x<=0){//到左边界了 return {val:true}; } } //碰撞检测 temp=this.collide(block,dis,dir); if(temp.val){ return temp; } if(!res || res.resDis==0 || (temp.resDis!=0 && temp.resDis0){ for(var i=0;i
到底后的处理
给当前的游戏对象的aliveModel数组,存取当前到底的模型所对应的4个小方块(执行render方法的时候就绘制出来)
在renderArr数组中此模型要删除
每次触底需要加入消除判断,符合条件就消除
绘制一个新的模型
绘制触底的模型方块
//绘制存底的图形 Game.prototype.aliveModelRender=function(){ var context=this.ctx; var disX=this.disX,disY=this.disY; context.save(); context.beginPath(); _.each(this.aliveModel,function(item){ if(item){ context.rect(item.x*disX+1,item.y*disY+1,disX-1,disY-1); //context.fillStyle=''; context.fill(); } }); context.restore(); }
消除行、积分、以及下降
//消除行 Game.prototype.clearBlock=function(){ var maxX=this.maxX,aliveModel=this.aliveModel; //将y相同的放在一起 var rowArr=[],rowObj={}; _.each(aliveModel,function(item,index){ if(item) { if(!rowObj[item.y]){ rowObj[item.y]=[]; } rowObj[item.y].push(index); } }); var that=this; var keys = Object.keys(rowObj),row,num=0; _.each(keys,function(k){ row = rowObj[k]; if(row.length>=maxX){//消除这行 _.each(row,function(r){ aliveModel.splice(r,1,undefined);//先用undefined代替 }) num++;//行数计数器 that.down(k,1);//清楚当前行 } }) //完成消除 for(var i=0;i自动往下移动、更新、显示时间、分数
//显示分数 Game.prototype.calcuScore=function(s){ this.score+=s; this.scoreEL.innerText='分数:'+this.score; } //显示时间 Game.prototype.calcuTime=function(){ if(this.moveCount%4==0){ this.time++; this.time_flag=false; this.timeEL.innerText='时间:'+this.time; } this.moveCount++; } //向下移动 Game.prototype.move=function(dir){ var curModel= this.currentModel; this.calcuTime(); var endFlag = this.end(); if(endFlag) { this.stop(); this.hasEnd=true; return ; } this.update(); this.render(); } //更新 Game.prototype.update=function(){ this.currentModel.move('ld'); }
给开始、结束按钮加入事件
var mainDiv = document.getElementById('mainDiv'); var score= document.getElementById('score'); var time= document.getElementById('time'); game.init(mainDiv,score,time); function start(){ game.start() } function stop(){ game.stop() }
Game.prototype.start=function(){ if(this.timmer) return ; if(this.hasEnd){//如果是结束则需要重新开始,暂停的话就继续游戏 this.restart(); } this.hasEnd=false; this.timmer = setInterval(this.move.bind(this),250);//开始定时任务 } //重新开始 Game.prototype.restart=function(){ this.renderArr=[];//待渲染对象存储数组 this.aliveModel=[];//用来存到底的model组合 this.score=0;//分数 this.time=0;//时间 this.moveCount=1;//计时控制器 this.clearCanvas(); this.draw(); } //停止任务 Game.prototype.stop=function(){ if(!this.timmer) return ; clearInterval(this.timmer);//清除定时任务 this.timmer=null; } //结束 Game.prototype.end=function(){ var aliveModel = this.aliveModel; for(var i=0;i源码如下:
HTML
分数:0 时间:0
JS
;(function(global){ var game= new Game(); function Game(el){ this.renderArr=[];//待渲染对象存储数组 this.aliveModel=[];//用来存到底的model组合 this.score=0;//分数 this.time=0;//时间 this.moveCount=1;//计时控制器 } Game.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;";//设置样式 var W = canvas.width = 300; //设置宽度 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=15;//x方向格子总数 this.maxY=20;//y方向格子总数 this.control();// this.draw();//绘制 } //绘制地图 Game.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=maxX){//消除这行 _.each(row,function(r){ aliveModel.splice(r,1,undefined);//先用undefined代替 }) num++;//行数计数器 that.down(k,1);//清楚当前行 } }) //完成消除 for(var i=0;i0){ dis=resDis; } //更新每一个block的位置 for(var i=0;i=maxY-1){//到底了 return {val:true}; } }else if(dir=='r'){ if(block.x>=maxX-1){//到右边界了 return {val:true}; } }else if(dir=='l'){ if(block.x<=0){//到左边界了 return {val:true}; } } //碰撞检测 temp=this.collide(block,dis,dir); if(temp.val){ return temp; } if(!res || res.resDis==0 || (temp.resDis!=0 && temp.resDis0){ for(var i=0;i以上是"怎么用JavaScript做俄罗斯方块游戏"这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!