开始自己手写一个好玩的俄罗斯方块吧,上变形,左右移动,下加速,空格瞬移等功能,无聊的时候学习下canvas,f12 修改分数,体验金手指的快乐吧

1、定义界面,和按钮

<div id="by">        <div id="title">            <!--//定义游戏界面-->            <canvas id="myCanvas" height="600" width="400" style="border: 2px solid #3c763d"></canvas>            <!--//定义下一个方块的预知框-->            <div id="title2">                <canvas id="Canvas" height="150" width="150" style="border: 2px solid #3c763d"></canvas>            </div>        </div>        <!--背景图-->        <div id="">            <img src="http://cnd.yinglingxuan.cn/75Z58PICq67_1024.jpg"  id="img" width="405px" height="602px" />        </div>    </div>    <!--按钮-->    <div class="aj">        <span onclick="tops()">上</span>        <span onclick="under()">下</span>        <span onclick="lefts()">左</span>        <span onclick="rights()">右</span>    </div>

2、js部分

1、先定义每个图形的形状和变化的形状,这里是使用多维数组的方式去保存它图形每个方块的位置(当然这里也可以用循环的方式)

        var data=[[[[1,0,0,0],[1,0,0,0],[1,1,0,0],[0,0,0,0]],[[1,1,1,0],[1,0,0,0],[0,0,0,0],[0,0,0,0]],[[1,1,0,0],[0,1,0,0],[0,1,0,0],[0,0,0,0]],[[0,0,1,0],[1,1,1,0],[0,0,0,0],[0,0,0,0]]],                   [[[1,0,0,0],[1,1,0,0],[1,0,0,0],[0,0,0,0]],[[1,1,1,0],[0,1,0,0],[0,0,0,0],[0,0,0,0]],[[0,0,1,0],[0,1,1,0],[0,0,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,0,0],[1,1,1,0],[0,0,0,0]]],                   [[[0,1,0,0],[0,1,1,0],[0,0,1,0],[0,0,0,0]],[[0,1,1,0],[1,1,0,0],[0,0,0,0],[0,0,0,0]],[[0,1,0,0],[0,1,1,0],[0,0,1,0],[0,0,0,0]],[[0,0,0,0],[0,1,1,0],[1,1,0,0],[0,0,0,0]]],                   [[[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]],[[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]],[[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]],[[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]]],                   [[[0,0,1,0],[0,1,1,0],[0,1,0,0],[0,0,0,0]],[[1,1,0,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]],[[0,0,1,0],[0,1,1,0],[0,1,0,0],[0,0,0,0]],[[1,1,0,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]]],                   [[[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]],[[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]],[[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]],[[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]]],                   [[[1,1,0,0],[1,0,0,0],[1,0,0,0],[0,0,0,0]],[[1,1,1,0],[0,0,1,0],[0,0,0,0],[0,0,0,0]],[[0,0,0,0],[0,0,1,0],[0,0,1,0],[0,1,1,0]],[[0,0,0,0],[0,0,0,0],[1,0,0,0],[1,1,1,0]]]          ];

2、定义图形的位置和每帧下落的速度

        var newX=120;//记录这个图形的左右位置        var count=0;   //记录下落的速度        var shape=0; //记录形状        var finallys=new Array(); //记录落下后停止的位置        var re=6;   //获取随机数方块        var fat=1;  //每帧的速度        var xyg=0;  //下一个方块        var dfen=0;//分数           //定义游戏界面        var c=document.getElementById("myCanvas");        var ctx=c.getContext("2d");        //下个方格的画布        var c2=document.getElementById("Canvas");        var ctx2=c2.getContext("2d");

3、定义组成图形的方法

        //组成图形的方法          function constitute(){              var Arr=new Array(); // 存储当前下来的方块位置              var y=0;   //记录每个小方块组成图形的小方块y下标--相加              for (var i=0;i<data[re][shape].length;i++) {                  var x=0; //记录每个小方块组成图形的小方块x下标                  for (var j=0;j<data[re][shape][i].length;j++) {                      x+=20;                      if(data[re][shape][i][j]==1&&Arr.length<4){ //每个图形都是四个小方块组成                           ctx.strokeStyle = "#000";                                           ctx.strokeRect(x+newX,y+count,20,20);                             ctx.fillStyle="#000000";  //定义颜色                           ctx.fillRect(x+newX,y+count,19,19);    //绘图                            var a={                               xs:x+newX,                               ys:y+count                           };                           Arr.push(a);   //记录图形位置                           if(Arr.length==4){ //图形形成后调用掉落完成后重新调用                               anew(Arr);                               return Arr;                           }                      }                  }                  y+=20;              };          }

3、判断掉落是否到底或者碰撞到上一个底部的方块

          //掉落完成后重新调用          function anew (arr){              var da=bottom(arr); //调用判断是否到底              if(da==1){  //如果返回1 则已经是到底部,                  finallys.push(arr); // 保存在底部的方块,方便碰撞判断                  count=0;  //恢复成原来的上下位置                  newX=120;  //恢复原来的左右位置                  re=xyg;     //当前的方块变成上一个的下一个                  xyg=Math.floor(Math.random()*7);  //重新随机获取当前的下一个                  ctx2.clearRect(0, 0, c.width,c.height);  //清除画布                  xygs();//重新绘制预知框的              }          }                                        //判断是否碰到下面的障碍物          function bottom(arr){   //判断是否掉落底部//返回1表示可以保存起来              for (var i =0;i<arr.length;i++) {                  if(arr[i].ys>=c.height-20){//首先判断是否到界面的底部                      /*console.log(arr);*/                      return 1;                  }                  for (var t=0;t<finallys.length;t++) {//再到保存的底部图形里面遍历出来判断是否与其他图形发生了碰撞                      for (var j=0;j<finallys[t].length;j++) {                          if(finallys[t][j].ys==arr[i].ys+20&&finallys[t][j].xs==arr[i].xs){                            /*console.log(arr);*/                            return 1;                          }                      }                  }              }              return 0;          }

4、下落到底部后的方块要保存起来,定义重新渲染的方法

          //用来组成下标已经堆积的格子          function  ground(finallys){              deletes();//判断是否到达顶部了, 顶部了就直接清除重新开始              for (var i=0;i<finallys.length;i++) {   //新图形开始的时候重新渲染已经到底部保存的图形                  for (var j=0;j<finallys[i].length;j++) {                       ctx.strokeStyle = "#000";                        ctx.strokeRect(finallys[i][j].xs,finallys[i][j].ys,20,20);                        ctx.fillStyle="#000000";  //定义颜色                       ctx.fillRect(finallys[i][j].xs,finallys[i][j].ys,19,19);    //画图                        if(finallys[i][j].ys<=20){                           this.finallys=new Array();                           count=0;                           constitute();   //调用组成画布的方法                           /*ctx.clearRect(0, 0, c.width,c.height);  //清除画布*/                           return;                       }                           }              }          }    

5、当横向一行满了后就可以清楚并得到对应的分数

      //判断是否组满一行达到清除的位置      function deletes(){        var c=600;//当前横向的宽度        var add=new Array;//记录宽度的每个方块        for (var i=0;i<c/20;i++) {//除以当前方块的宽度获得每个横度的方块位置            c=c-20;            add.push(c);        }        for (var a=0;a<add.length;a++) {//判断每个横向的方块是否堆积满了            var cou=0;            for (var t=0;t<finallys.length;t++) {                  for (var j=0;j<finallys[t].length;j++) {                    if(add[a]==finallys[t][j].ys){                        cou++;                    }                  }              }            if(cou>=20){ //如果横向满了调用清除的方法                qc(add[a]);//                cou=0;            }        }    }      //一行满了后清除和上面的向下增加移动      function qc(add){          for (var t=0;t<finallys.length;t++) {              for (var j=0;j<finallys[t].length;j++) {                if(add==finallys[t][j].ys){                    finallys[t].splice(j,1);                    dfen=dfen+10;                    j--;                }              }          }          for (var t=0;t<finallys.length;t++) {              for (var j=0;j<finallys[t].length;j++) {                if(finallys[t][j].ys<add){                    finallys[t][j].ys=finallys[t][j].ys+20;                }              }          }      }

6、碰撞检测

          //判断不能掉出围起来的范围          function crash(count,e){ //count 下落的位置, e 表示当前是什么按钮操作              var newCount=0;  //判断是否有下降的数据有就下降              if(count!=0){                  newCount=count;              }              var y=0;   //记录组成形状的位置--相加              var r=0;              var make=-1;              for (var i=0;i<data[re][shape].length;i++) {                  var x=0;                   for (var j=0;j<data[re][shape][i].length;j++) {                      x+=20;                      if(data[re][shape][i][j]==1){                          //防止变形的时候溢出                          if(e==38&&x+newX<0||x+newX>c.width-20){                              if(x+newX<0){                                  newX=newX+20;                                  r=1;                              }else{                                  newX=newX-20;                                  r=2;                              }                          }                          if(e==38){                              if(y+count>c.height-20){                                  if(shape!=0){                                    shape=shape-1;                                }else{                                    shape=3;                                }                              }                          }                                                    ////防止突出右边                          if(e==39&&c.width-20<x+newX+20){                              make=1;                          }                          //防止突出左边                          if(e==37&&x+newX-20<0){                              make=1;                          }                          if(y+newCount>c.height-20){                              count=count-20;                          }                          var ys=(y+count)%20; //下落的时候可能会一直按着 速度快会直接插到下面,所以这里要求余,当到这个方块的位置的时候取整判断                          var es=20-ys;                          var newCount=y+count+es;                                                    for (var t=0;t<finallys.length;t++) {                              for (var j1=0;j1<finallys[t].length;j1++) {                                if(finallys[t][j1].ys==newCount&&finallys[t][j1].xs==x+newX+20&&e==39){                                    newX=newX-20;                                }                                if(finallys[t][j1].ys==newCount&&finallys[t][j1].xs==x+newX-20&&e==37){                                    newX=newX+20;                                }                                if(finallys[t][j1].ys+20==newCount&&finallys[t][j1].xs==x+newX&&e==38){                                    if(shape!=0){                                        shape=shape-1;                                    }else{                                        shape=3;                                    }                                    if(r==1){                                        newX=newX-20;                                    }                                    if(r==2){                                        newX=newX+20;                                    }                                }                              }                          }                      }                  }                  y+=20;              };                            if(e==39&&make==-1){                  newX=newX+20;              }              if(e==37&&make==-1){                  newX=newX-20;              }          }

7、按钮操作

        $(document).keydown(function(e){  //电脑键盘的            if(e.keyCode==39){  //右                crash(count,e.keyCode);//判断是否可以加到右边            }else if(e.keyCode==37){  //左                //判断是否可以加到左边                crash(count,e.keyCode);            }else if(e.keyCode==40){   //下                var i=count%10;                count=count-i;                fat=10;                            }else if(e.keyCode==38){   //上               shape++;               if(shape>3){                   shape=0;               }               crash(count,e.keyCode);  //防止变形溢出            }else if(e.keyCode==32){                var i=count%20;                count=count-i;                for (var t=0;t<400;t++) {                    count=count+10;                    var arr=constitute();                    var e=bottom(arr);                    if(e==1){                        break;                    }                }            }        });        //////////////////////////// 手机端的按钮        function under(){              var i=count%10;            count=count-i;            fat=10;            setTimeout(function(){                fat=1;            },100)          }          document.onkeyup=function(){            fat=1;        }          function tops(){             shape++;           if(shape>3){               shape=0;           }           crash(count,38);  //防止变形溢出          }          function lefts(){              //判断是否可以加到左边            crash(count,37);          }          function rights(){              crash(count,39);//判断是否可以加到右边          }

8、定义绘制预知框的方法,如上面绘制的方法一样,只是对应的canvas不同

          //预知框里面的绘制          function xygs(){              var y=0;   //记录组成形状的位置--相加              for (var i=0;i<data[xyg][shape].length;i++) {                  var x=0;                   for (var j=0;j<data[xyg][shape][i].length;j++) {                      x+=20;                      if(data[xyg][shape][i][j]==1){                           ctx2.strokeStyle = "#000";                           ctx2.strokeRect(x+30,y+50,20,20);                           ctx2.fillStyle="#000000";  //定义颜色                           ctx2.fillRect(x+30,y+50,19,19);    //画图                       }                  }                  y+=20;              };          }

9、开始运行的方法

      function  dy(){            ctx.clearRect(0, 0, c.width,c.height);  //清除画布            constitute();   //调用组成画布的方法            count=count+fat;   // 下落的速度            ground(finallys);    //调用已经在底部的方块的方法            ctx.font="20px 微软雅黑";            ctx.fillText("得分:"+dfen+"",20,30);            requestAnimationFrame(dy);   //调用循环运行        }        requestAnimationFrame(dy);  //开始运行每一帧                if(finallys.length==0){ //获取第一个预知框            xyg=Math.floor(Math.random()*7);//随机获取            xygs();//调用预知框的渲染        }        constitute()//开始绘制