lufylegend引擎俄罗斯方块的实现

来源:互联网 发布:淘宝店铺更改所在地 编辑:程序博客网 时间:2024/06/05 12:00

lufylegend引擎俄罗斯方块的实现

  1. 旋转坐标的实现
    俄罗斯方块的实现第一步就是旋转坐标的获得,下面将会详细写出推导过程,首先必须要分配好方块的构成,这里需要用4个精灵来形成基本的block,如长方形,L形等,之后就是选择原点坐标和各点的相对坐标,这里先把选转的坐标公式推导一下,如下图:
    旋转β度
    旋转前的坐标为x,y,旋转前的角度为ζ度,旋转后的坐标为x1,y1,旋转后的角度为(ζ+β)度,因为旋转后,该点到原点的距离并不会发生改变,所以我们需要先用已只条件得到该点到原点的距离h=y/sinζ=x/cosζ
    那么对应的旋转后距离就是h1=y1/sin(ζ+β)=x1/cos(ζ+β);因为h1=h,所以可以推导出y1/sin(ζ+β)=x1/cos(ζ+β)=y/sinζ=x/cosζ;
    接下来要用到和角公式
    sin(a+b)=sinacosb+sinbcosa
    cos(a+b)=cosacosb-sinasinb
    y1=y*sin(ζ+β)/sinζ=y(sinζcosβ+sinβcosζ)/sinζ=ycosβ+ycosζ/sinζ*sinβ;
    又因为y/x=sinζ/cosζ,所以x=ycosζ/sinζ,所以y1=ycosβ+xsinβ
    以此类推x1=xcos(ζ+β)/cosζ=x(cosζcosβ-sinζsinβ)/cosζ=xcosβ-xsinζ/cosζ*sinβ=xcosβ-ysinβ,即x1=xcosβ-ysinβ
    这样第一步旋转公式的推导就ok了,接下来是应用了,这里选择将第三个方块的起始x,y作为坐标原点,如下图以L形方块为例:这里写图片描述
    可以看到第一个为初始L形,此时第三个方块的坐标看做0,0,那么剩余方块坐标为1号方块(-1,1),2号方块为(-1,0),4号方块为(1,0),则根据之前的旋转公式可以得到,x1=xcosβ-ysinβ,y1=ycosβ+xsinβ,此中p为90度,则实际x1=-y,y1=x,所以旋转后坐标1号方块为(-1,-1),2号方块为(0,-1),4号方块为(0,1),以此类推可以求出第三次旋转,第四次旋转的坐标。
    所以实现的代码为
javascriptfor(var i=0;i<4;i++){                //求得相对坐标                var x=sprite[i].x-sprite[2].x;                var y=-(sprite[i].y-sprite[2].y);                //求出相对坐标后在换算成实际坐标                sprite[i].x=-y+sprite[2].x;                sprite[i].y=-x+sprite[2].y;            }

因为实际lufylegend的引擎坐标系是以左上角为原点的,所以这里做了一下换算,将坐标系反过来了

这样旋转后的方块就可以很方便的画出来了

  1. 方块的最下方的判断
    对于俄罗斯方块来说都有着最低层,并且之后检测碰撞的方便都会用到方块的最低点的坐标,所以接下来的工作就是实现这个目的,以L形为例子,初始的最低点为,第一个方块的Y坐标就是方块的最低点,所以在初始化方块的时候可以事先将maxY赋值成1,之后在方块的下落过程中,方块的坐标是在不断变动的,以及方块旋转后其最低点的坐标也是会发生变化的。这里需要考虑到这两个条件,所以接下来就要修改上面的旋转函数和方块的下落函数,并在其中求最大的Y坐标:
javascript//旋转函数for(var i=0;i<4;i++){                var x=sprite[i].x-sprite[2].x;                var y=-(sprite[i].y-sprite[2].y);                sprite[i].x=-y+sprite[2].x;                sprite[i].y=-x+sprite[2].y;                //求最大X的坐标                if(sprite[maxX].x<sprite[i].x)                    maxX=i;                //求最大Y的坐标                if(sprite[maxY].y<sprite[i].y)                    maxY=i;            }
javascriptif(s.childList[maxY].y<290){    for(var i=0;i<s.childList.length;i++){               s.childList[i].y=s.childList[i].y+10;            //更新最大的Y坐标            if(s.childList[maxY].y<=s.childList[i].y){                maxY=i;            }    }    }else{            s.activemode=false;    }

这样方块的最下方的判断就完成了

3.方块的生成
俄罗斯方块中是由方块的掉落来进行游戏的,所以需要对方块进行生成,如果是写定的方块的话容易产生一种厌烦感,所以这里需要对方块进行随机生成,首先需要确定是第一个方块的位置,这个很容易,因为Y坐标必定是0,所以只需要对x进行随机就行了
var x=Math.round(Math.random()*13)*10;
var y=0;
这样就可以生成一个0,130的随机数,需要注意一下math.random()是产生0到1的随机数,如果不用math.round的话,产生的x值并不是10的整数倍,所以需要在这里先用math.round得到一个整数,之后再乘以10,获得就是0,10,20,30.。。130的随机数
而对于下一个方块来说,坐标取值只有4种,[-10,0],[10,0],[0,10],[0,-10],也就是上下左右4个领接位置,但是当方块坐标为0,或者130时为了使方块不跃出边界,就只能选择3方向的方块,0:[10,0],[0,10],[0,-10],130:[-10,0],[0,10],[0,-10],这样就确定好了3种情况所能随机的方块位置了,还需要注意一下的就是之前的方块位置,避免两个方块差生在同一个位置,所以源代码如下:

LBlock.prototype.onshow=function(){    var s=this;     var x=Math.round(Math.random()*13)*10;    //var x=200;    var y=0;    var i;    var a=new Array();    var save=new Array();    a[0]=[x,y];    save=[[x,y],[-1,-1],[-1,-1],[-1,-1]];    for(i=1;i<4;i++){        if(a[i-1][0]==130){            var b=[[-10,0],[0,10],[0,-10]]        }else if(a[i-1][0]==10){            var b=[[10,0],[0,10],[0,-10]]        }else{            var b=[[-10,0],[10,0],[0,10],[0,-10]];        }        var select=Math.round(Math.random()*(b.length-1));        var m=a[i-1][0]+b[select][0];        var n=a[i-1][1]+b[select][1];        if(find([m,n],save)){            a[i]=[m,n]            save[i]=[m,n]        }else{            b.splice(select,1);            select=Math.round(Math.random()*(b.length-1));            m=a[i-1][0]+b[select][0];            n=a[i-1][1]+b[select][1];            a[i]=[m,n]        }    }    var sprite=[];    for(i=0;i<4;i++){        sprite[i]=new LSprite();        sprite[i].x=a[i][0];        sprite[i].y=a[i][1];        sprite[i].graphics.drawRect(2,"blue",[0,0,10,10],true,"green");        s.addChild(sprite[i]);          }}

这样就可以随机生成不同坐标的不一样形状的方块了

4.方块的碰撞检测
俄罗斯方块游戏中的重点,方块与方块,方块与边界的碰撞,在整个游戏中需要注意以下这几种情况1.旋转时的碰撞检测,如果旋转后的坐标上有方块或边界就不能进行旋转 2.左右移动时的碰撞检测,3.向下移动时的碰撞检测
首先需要定义一个用来存放方块的容器,这里采用高200,宽120的大小容器,定义为一个20,14的数组
var mapData=[[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0]
]
初始值全为0,当方块停止后,就将对应位置的数组值置为1
1.向下移动时的碰撞检测
因为方块需要一起进行移动,所以要优先判断所有方块是否由碰撞,如有就不移动方块,否则会出现一部分方块停止后,另一部分依然正常运动的情况,所以这里采用先对所有方块的碰撞进行判断,之后再移动方块
LBlock.prototype.onframe=function(){
var s=this;
var flag=true;
if(s.childList[maxY].y<190){
for(var i=0;i

 flag=true;           for(var i=0;i<4;i++){                var x=sprite[i].x-10;                var y=sprite[i].y;                var m=190-y;                var n=x;                if(y>=0){                if((mapData[Math.floor(m/10)][Math.floor(n/10)]==1)||(n>130)||(n<0)||(m>190)){                     flag=false;                  }                }            }            if(flag){                for(var i=0;i<4;i++){                sprite[i].x=sprite[i].x-10;                if(sprite[maxX].x<sprite[i].x)                    maxX=i;                if(sprite[maxY].y<sprite[i].y)                    maxY=i;                }            }

3.旋转判定

if(button==65){            //以sprite2为坐标原点            flag=true;            for(var i=0;i<4;i++){                var x=sprite[i].x-sprite[2].x;                var y=-(sprite[i].y-sprite[2].y);                var m=-y+sprite[2].x;                var n=190-(-x+sprite[2].y);                if((mapData[Math.floor(n/10)][Math.floor(m/10)]==1)||(m>130)||(m<0)||(n>190)){                     flag=false;                  }            }            if(flag){                for(var i=0;i<4;i++){                    var x=sprite[i].x-sprite[2].x;                var y=-(sprite[i].y-sprite[2].y);                sprite[i].x=-y+sprite[2].x;                sprite[i].y=-x+sprite[2].y;                if(sprite[maxX].x<sprite[i].x)                    maxX=i;                if(sprite[maxY].y<sprite[i].y)                    maxY=i;                }            }

5.消行

上述工作完成后,对于俄罗斯方块而言,仅缺少的就是消行,因为之前已经定义了mapData这个容器数组,所以只需要在onframe函数中,检测mapData中一横行的数值是否全为,如果全为1既消去整一行,并删掉改行的方块,为了实现这个,首先需要对s.result这个在方块停止的函数进行改动,因为对于blocklayer来讲下属的精灵类非常不好进行查询,所以这里在停止时会删掉这个部分,并将这部分的值赋给一个事先定义好的mapsprite数组,这样定义的话,数组就是有序的,方便进行删除,下面就是s.result函数的修改后的代码,在将坐标获得后直接拿掉改对象,改用mapsprite进行绘制

LBlock.prototype.result=function(){    var s=this;    var b=[];    for(var i=0;i<s.childList.length;i++){               var x=s.childList[i].x;            var y=190-s.childList[i].y;            //求得数组坐标            var m=Math.round(x/10);            var n=Math.round(y/10);            mapData[n][m]=1;            mapsprite[n][m]=s.childList[i];            mapsprite[n][m].graphics.drawRect(2,"blue",[0,0,10,10],true,"green");            //mapLayer.addChild(mapsprite[n][m]);            b[i]=[n,m];    }       for(var i=0;i<b.length;i++){        mapLayer.addChild(mapsprite[b[i][0]][b[i][1]]);    }    s.remove();}

这一步完成后游戏中就可以获得行对应行,列对应列的有序数组了,这样删除起来就方便多了,接下来是删除函数,对于俄罗斯方块的消行来说,需要完成两个步骤,第一个步骤就是将mapData后一行的值赋给前一行,并将最后一行的所有值置为0,第二个步骤就是将mapsprite绘制的方块全部下移一行,这两个步骤完成后,消行也就完成了,所以代码需要这样写:

   function canclemap(n){      for(var i=0;i<mapsprite[n].length;i++){          mapsprite[n][i].remove();      }      for(var i=n;i<mapData.length;i++){          if(i<mapData.length-1){              mapData[i]=mapData[i+1];              for(var j=0;j<mapsprite[n].length;j++){                  mapsprite[i+1][j].y=mapsprite[i+1][j].y+10;                  mapsprite[i]=mapsprite[i+1];              }          }else{              mapData[i]=[0,0,0,0,0,0,0,0,0,0,0,0,0,0];              for(var j=0;j<mapsprite[n].length;j++){                  mapsprite[i][j].remove();              }          }      }   }

源代码:
index.php

<!DOCTYPE html>  <html lang="en">      <head>      <meta charset="utf-8" />      <title>LTetris</title>      <script type="text/javascript" src="lufylegend.js-lufylegend-1.9.7/lufylegend-1.9.7.min.js"></script>       <script src="jquery/jquery-1.8.3.js"></script>    <script src="tetrisblock.js"></script>    <script>      LInit(30,"legend",450,320,gameInit);    LGlobal.setDebug(true);      var backLayer,loadingLayer,blockLayer,mapLayer;    var block;//方块    var point;//分数    var next;    var nextLayer,nextblockLayer;//下一个方块    //整个方框的大小,长20,宽14,即长200,宽140    var mapData=[[0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0],                 [0,0,0,0,0,0,0,0,0,0,0,0,0,0]    ]    var mapsprite=new Array();    var totalnum=1;//同时只有一个方块    /*var loadData = [          {name:"cr",path:"./images/charc.jpg"},           {name:"map",path:"./images/map.jpg"},        {name:"money",path:"./images/bird.png"},        {name:"photo1",path:"./images/66RPG_002_f.png"},        {name:"photo2",path:"./images/66RPG_005_f.png"}    ];     function main(){          //加入进度条          loadingLayer = new LoadingSample3();           addChild(loadingLayer);           //加载图片并显示进度          LLoadManage.load(              loadData,             function(progress){                  loadingLayer.setProgress(progress);              },              gameInit          );      }  */    function gameInit(){        initmap();        backLayer = new LSprite();          backLayer.graphics.drawRect(2,"green",[0, 0, 140,200],true,"white");        addChild(backLayer);         blockLayer=new LSprite();        backLayer.addChild(blockLayer);        mapLayer=new LSprite();        backLayer.addChild(mapLayer);        //添加分数区        //添加下一个方块的提示区        //block=new LBlock();        //blockLayer.addChild(block);        //加入动画和按键事件监听           backLayer.addEventListener(LEvent.ENTER_FRAME,onframe);        LEvent.addEventListener(LGlobal.window, LKeyboardEvent.KEY_DOWN,move);         LEvent.addEventListener(LGlobal.window, LKeyboardEvent.KEY_UP,stop);    }    function addblock(){       if(totalnum==1){           block=new LBlock();           blockLayer.addChild(block);           totalnum--;       }    }    function onframe(){       addblock();       if(block.mode!="die"){           block.onframe();                   }else{           totalnum++;       }       for(var i=0;i<mapData.length;i++){       if(mapData[i].toString()==[1,1,1,1,1,1,1,1,1,1,1,1,1,1].toString()){           canclemap(i);       }      }       checkEnd();    }    function initmap(){         for(var i=0;i<20;i++){           mapsprite[i]=new Array();           for(var j=0;j<14;j++){               mapsprite[i][j]=new LSprite();           }       }    }   function move(e){           block.onbutton(e.keyCode);   }   function canclemap(n){      for(var i=0;i<mapsprite[n].length;i++){          mapsprite[n][i].remove();      }      for(var i=n;i<mapData.length;i++){          if(i<mapData.length-1){              mapData[i]=mapData[i+1];              for(var j=0;j<mapsprite[n].length;j++){                  mapsprite[i+1][j].y=mapsprite[i+1][j].y+10;                  mapsprite[i]=mapsprite[i+1];              }          }else{              mapData[i]=[0,0,0,0,0,0,0,0,0,0,0,0,0,0];              for(var j=0;j<mapsprite[n].length;j++){                  mapsprite[i][j].remove();              }          }      }   }  function checkEnd(){      for(var j=0;j<14;j++){          if(mapData[19][j]==1){              alert("game over");          }      }  }    </script>       </head>      <body>              <div id="legend"></div>      </body>  </html>

tetrisblock.js

var maxX=0;var maxY=0;var speed=1;//初始为5function LBlock(){    var s=this;    base(s,LSprite,[]);    s.i=Math.round(Math.random()*6+1);    //s.i=7;    //1为竖形,2为L形,3位反L形,4为正方形,5为楼梯形,6为反楼梯形,7为T形    s.status=1;//1为默认,2为    s.activemode=true;//true可操作,false不可    s.mode="live";    s.onshow();}LBlock.prototype.setspeed=function(speedc){    speed=speedc;}LBlock.prototype.getvalue=function (){    var s=this;    return s;}LBlock.prototype.onframe=function(){    var s=this;    var flag=true;    if(s.childList[maxY].y<190){       for(var i=0;i<s.childList.length;i++){           if(s.childList[i].y>=0){               var m=Math.floor((190-(s.childList[i].y+speed))/10);               var n=Math.floor(s.childList[i].x/10);               if(mapData[m][n]==1){                   s.activemode=false;                   s.mode="die";                   s.result();                     flag=false;                 }           }                  }       if(flag){            for(var i=0;i<s.childList.length;i++){            s.childList[i].y=s.childList[i].y+speed;            if(s.childList[maxY].y<=s.childList[i].y){                maxY=i;            }            }       }    }else{            s.activemode=false;            s.mode="die";            s.result();    }}LBlock.prototype.result=function(){    var s=this;    var b=[];    for(var i=0;i<s.childList.length;i++){               var x=s.childList[i].x;            var y=190-s.childList[i].y;            //求得数组坐标            var m=Math.round(x/10);            var n=Math.round(y/10);            mapData[n][m]=1;            mapsprite[n][m]=s.childList[i];            mapsprite[n][m].graphics.drawRect(2,"blue",[0,0,10,10],true,"green");            //mapLayer.addChild(mapsprite[n][m]);            b[i]=[n,m];    }       for(var i=0;i<b.length;i++){        mapLayer.addChild(mapsprite[b[i][0]][b[i][1]]);    }    s.remove();}LBlock.prototype.onbutton=function(button){    var s=this;    var flag=true;    if(s.activemode){    var sprite=[];    for(i=0;i<4;i++){        sprite[i]=new LSprite();        sprite[i]=s.childList[i];    }    //旋转    if(button==65){            //以sprite2为坐标原点            flag=true;            for(var i=0;i<4;i++){                var x=sprite[i].x-sprite[2].x;                var y=-(sprite[i].y-sprite[2].y);                var m=-y+sprite[2].x;                var n=190-(-x+sprite[2].y);                if((mapData[Math.floor(n/10)][Math.floor(m/10)]==1)||(m>130)||(m<0)||(n>190)){                     flag=false;                  }            }            if(flag){                for(var i=0;i<4;i++){                    var x=sprite[i].x-sprite[2].x;                var y=-(sprite[i].y-sprite[2].y);                sprite[i].x=-y+sprite[2].x;                sprite[i].y=-x+sprite[2].y;                if(sprite[maxX].x<sprite[i].x)                    maxX=i;                if(sprite[maxY].y<sprite[i].y)                    maxY=i;                }            }    }else if(button==37){    //左移右移           flag=true;           for(var i=0;i<4;i++){                var x=sprite[i].x-10;                var y=sprite[i].y;                var m=190-y;                var n=x;                if(y>=0){                if((mapData[Math.floor(m/10)][Math.floor(n/10)]==1)||(n>130)||(n<0)||(m>190)){                     flag=false;                  }                }            }            if(flag){                for(var i=0;i<4;i++){                sprite[i].x=sprite[i].x-10;                if(sprite[maxX].x<sprite[i].x)                    maxX=i;                if(sprite[maxY].y<sprite[i].y)                    maxY=i;                }            }    }else if(button==39){    //左移右移           flag=true;           for(var i=0;i<4;i++){                var x=sprite[i].x+10;                var y=sprite[i].y;                var m=190-y;                var n=x;                if(y>=0){                if((mapData[Math.floor(m/10)][Math.floor(n/10)]==1)||(n>130)||(n<0)||(m>190)){                     flag=false;                  }                }            }            if(flag){                for(var i=0;i<4;i++){                sprite[i].x=sprite[i].x+10;                if(sprite[maxX].x<sprite[i].x)                    maxX=i;                if(sprite[maxY].y<sprite[i].y)                    maxY=i;                }            }    }else if(button==40){    //左移右移           flag=true;           for(var i=0;i<4;i++){                var x=sprite[i].x;                var y=sprite[i].y+20;                var m=190-y;                var n=x;                if(y>=0){                if((mapData[Math.floor(m/10)][Math.floor(n/10)]==1)||(n>130)||(n<0)||(m>190)){                     flag=false;                  }                }            }            if(flag){                for(var i=0;i<4;i++){                sprite[i].y=sprite[i].y+20;                if(sprite[maxX].x<sprite[i].x)                    maxX=i;                if(sprite[maxY].y<sprite[i].y)                    maxY=i;                }            }    }    }}function find(f,a){    for(var i=0;i<a.length;i++){        if((a[i][1]==f[1])&&(a[i][0]==f[0])){            return false;        }    }    return true;}LBlock.prototype.onshow=function(){    var s=this;     var x=Math.floor(Math.random()*13)*10;    //var x=200;    var y=0;    var i;    var a=new Array();    var save=new Array();    a[0]=[x,y];    save=[[x,y],[-1,-1],[-1,-1],[-1,-1]];    for(i=1;i<4;i++){        if(a[i-1][0]==130){            var b=[[-10,0],[0,10],[0,-10]]        }else if(a[i-1][0]==0){            var b=[[10,0],[0,10],[0,-10]]        }else{            var b=[[-10,0],[10,0],[0,10],[0,-10]];        }        var select=Math.round(Math.random()*(b.length-1));        var m=a[i-1][0]+b[select][0];        var n=a[i-1][1]+b[select][1];        if(find([m,n],save)){            a[i]=[m,n]            save[i]=[m,n]        }else{            b.splice(select,1);            select=Math.round(Math.random()*(b.length-1));            m=a[i-1][0]+b[select][0];            n=a[i-1][1]+b[select][1];            a[i]=[m,n];        }    }    var sprite=[];    for(i=0;i<4;i++){        sprite[i]=new LSprite();        sprite[i].x=a[i][0];        sprite[i].y=a[i][1];        sprite[i].graphics.drawRect(2,"blue",[0,0,10,10],true,"green");        s.addChild(sprite[i]);          }}
0 0
原创粉丝点击