JavaScript实现俄罗斯方块游戏进程分析和源代码共享
看《编程之美》:“程序虽然难写,但是很精彩。要想把程序写好,需要写一些基础知识,包括编程语言、数据结构和算法。一个写得好的程序,需要缜密的逻辑思维能力和良好的梳理基础,熟悉编程环境和编程工具。”
学了几年计算机,你有没有爱上过编程?换句话说,如果你不试着自己写一个游戏,你就不爱编程。
俄罗斯方块引起的轰动和经济价值,可以说是游戏史上的一件大事。看似简单,却变化多端,让人上瘾。我相信大多数学生都痴迷于此。
游戏规则
1.放置小方块的平面虚拟场,标准尺寸:行宽10,列高20,以每个小方块为单位。
2.由四个小方块组成的一组规则图形,英文称为Tetromino,中文称为square,以S、Z、L、J、I、O、T七个字母的形状命名.
I:一次最多消除四层
j(左右):最多取消三层,或者取消两层
l:最多消除三层,或者消除两层
o:取消一两层
s(左右):最多两层,容易造成破洞
z(左右):最多两层,容易造成破洞
汤:最多两层
盒子会慢慢地继续从该区域的顶部落下。玩家可以90度为单位旋转箱子,以格子为单位左右移动箱子,加速箱子下落。当一个盒子移动到该区域的底部或落在另一个盒子上时,它将被固定在那里,一个新的盒子将出现在该区域上方并开始下落。当区域中的一排水平网格被方块完全填满时,该行将消失并成为玩家的分数。同时删除的列越多,得分指数越高。
分析和解决方案
在每个方块下落的过程中,我们可以做到:
1)向右旋转
2)水平移动到某一列
3)垂直下落至底部
首先,需要一个二维数组,区域[18][10],来表示18*10的游戏区域。其中,数组中的值0表示空,1表示有一个框。
正方形有七种,每种有四个方向。定义活动块[4]。在编译之前,计算这个数组的值,并直接在程序中使用。
困难
1)边界检查。
//检查左边界,试着向左移动一个,看看是否合法。函数CheckLeftBorder(){ for(var I=0;iactiveBlock.lengthi ){ if(activeBlock[i]。y==0){返回false} if(!isCellValid(activeBlock[i])。x,activeBlock[i]。y-1)){返回false} }返回true}//同样,需要检测右边界和底界
2)旋转需要数学逻辑,一个点相对另一个点旋转90度。3)计时和监控键盘事件的机制使游戏自动运行。
//start函数begin(e){ e . disabled=true;状态=1;TBL=document . getelementbyid(' area ');if(!generateBlock()){ alert('游戏结束!');状态=2;返回;} paint();timer=setInterval(moveDown,1000);} document . onkeydown=key control;
程序过程
1)用户点开始-构建活动图并设置计时器。
//可以改变当前活动的可以左右上下移动的方框。当它触底时,它会更新区域;var activeBlock//生产块形状,有7种基本形状。函数generateBlock(){ activeBlock=null;活动块=新数组(4);//随机生成0-6个数组,代表7种形式。var t=(math . floor(math . random()* 20)1)% 7;switch(t){ case 0: { activeBlock[0]={ x :0,y :4 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:0,y :5 };activeBlock[3]={x:1,y :5 };打破;}//省略部分代码....case6: {活动块[0]={x:0,y :5 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:1,y :5 };activeBlock[3]={x:1,y :6 };打破;} }//检查新产生的四个小方块是否可以放在初始化位置。for(var I=0;i4;i ){ if(!isCellValid(activeBlock[i])。x,activeBlock[i]。y)){返回false} }返回true}2)每次向下运动后,检查是否见底。如果它触底,尝试取消。
//取消行功能删除行(){ var lines=0;for(var I=0;i18I){ var j=0;for(;j10j){ if(area[I][j]==0){ break;} } if(j==10){ line;如果(我!=0){ for(var k=I-1;k=0;k - ){面积[k ^ 1]=面积[k];} } area[0]=generateBlankLine();} }返回线路;}
3)之后,构建一个活动图并设置一个定时器。
翻译
有待优化
1)设置不同形状方块的颜色。
思考:在创建块的功能中,设置了activeBlockColor的颜色,七种不同形状的块的颜色是不一样的(除了修改generateBlock方法,paintarea方法也需要修改。因为一开始考虑不周,去掉一行后,在重画方块的时候统一了颜色。因此,可以考虑从表中删除N行,然后在顶部添加N行,以确保不消除框的完整性。
2)当前框落下时,可以提前勾选下一个框。
思考:generateBlock方法分为两部分,一部分用来随机尝试下一块,另一部分用来缓存当前要描绘的块。当前块触底并固定后,下一块开始绘制,再次随机生成新块。如此重复。
完整的HTML源代码:
!doctype html head title ris/title meta charset=' utf-8 ' style * { font-family 3330 '何首乌";}。车顶容器{宽度: 230像素高度: 400像素相对位置:左: 50%;左边距:-115像素;前: 40%;页:1:} # tr区域td{宽度: 20px高度: 20像素边界:1像素固体# CCC }/样式/头部主体div class=' tetriccontainer '输入类型=' button '值='你好onclick='begin(此处);'/何人3330 span id=' score ' 0/span table id=' area '单元格间距=' 0 '单元格填充=' 0 '边框=' 1 '样式='边框塌陷3330塌陷' trtd/TD/TD/TD/TD/TD/TD/TD/TD/trtd/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD/TD是阿云俄罗斯方块喜曰:
/** * JS俄罗斯方块游戏v 1.0*///表示页面中的桌子,这个桌子就是将要显示游戏的主面板var tbl/游戏状态0: 未开始;一运行;2中止;定义变量状态=0;//定时器,定时器内将做下移操作定义变量计时器;//分数定义变量得分=0;//区域是一个18*10的数组,也和页面的桌子对应。初始时都为0, 如果被占据则为1 var区域=新数组(18);for(var I=0;i18i){ 0面积[i]=新数组(10);} for(var I=0;i18I){ for(var j=0;j10j){ 0面积[I][j]=0;} } //当前活动的方块,它可以左右下移动,变型。当它触底后,将会更新面积;var activeBlock//生产方块形状,有七种基本形状函数generateBlock(){ activeBlock=null;活动块=新数组(4);//随机产生0-6数组,代表七种形态var t=(数学。地板(数学。random()* 20)1)% 7;switch(t){ case 0: { activeBlock[0]={ x :0,y :4 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:0,y :5 };activeBlock[3]={x:1,y :5 };打破;} case 1: { activeBlock[0]={ x :0,y :3 };activeBlock[1]={x:0,y :4 };activeBlock[2]={x:0,y :5 };activeBlock[3]={x:0,y :6 };打破;} case 2: { activeBlock[0]={ x :0,y :5 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:1,y :5 };activeBlock[3]={x:2,y :4 };打破;} case 3: { activeBlock[0]={ x :0,y :4 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:1,y :5 };activeBlock[3]={x:2,y :5 };打破;} case 4: { activeBlock[0]={ x :0,y :4 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:1,y :5 };activeBlock[3]={x:1,y :6 };打破;} case 5: { activeBlock[0]={ x :0,y :4 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:2,y :4 };activeBlock[3]={x:2,y :5 };打破;} case 6: { activeBlock[0]={ x :0,y :5 };activeBlock[1]={x:1,y :4 };activeBlock[2]={x:1,y :5 };activeBlock[3]={x:1,y :6 };打破;} } //检查刚生产的四个小方格是否可以放在初始化的位置for(var I=0;i4;i ){ if(!isCellValid(activeBlock[i]).x,activeBlock[i].y)){ 0返回false} }返回true} //向下移动函数moveDown(){ //检查底边界if(CheckBottonBorder()){//没有触底,则擦除当前图形,erase();//更新当前图形坐标for(var I=0;i4;i ){ activeBlock[i].x=活动块[i].x1;} //重画当前图形paint();} //触底,else{ //停止当前的定时器,也就是停止自动向下移动clearInterval(计时器);//更新区域数组updatearea();//消行var line=delete line();//如果有消行,则如果(台词!=0){ //更新分数分数=分数线* 10;updateScore();//擦除整个面板erase era();//重绘面板油漆区();} //产生一个新图形并判断是否可以放在最初的位置如果(!generateBlock()){ alert('游戏结束!');状态=2;返回;} paint();//定时器,每隔一秒执行一次下移计时器=setInterval(moveDown,1000) } } //左移动函数moveLeft(){ if(CheckLeftBorder()){ erase();for(var I=0;i4;i ){ activeBlock[i].y=活动块[i].y-1;} paint();} } //右移动函数moveRight(){ if(CheckrightBorder()){ erase();for(var I=0;i4;i ){ activeBlock[i].y=活动块[i].y1;} paint();} } //旋转,因为旋转之后可能会有方格覆盖已有的方格。//先用一个tmpBlock,把activeBlock的内容都拷贝到tmpBlock,//对tmpBlock尝试旋转,如果旋转后检测发现没有方格产生冲突,则//把旋转后的tmpBlock的值给活动块.函数rotate(){ var tmpBlock=new Array(4);for(var I=0;i4;i ){ tmpBlock[i]={x:0,y :0 };} for(var I=0;i4;i ){ tmpBlock[i].x=活动块[i].x;tmpBlock[i].y=活动块[i].y;} //先算四个点的中心点,则这四个点围绕中心旋转90度。
var cx=Math.round((tmpBlock[0]).x tmpBlock[1].x tmpBlock[2]。x tmpBlock[3].x)/4);var cy=Math.round((tmpBlock[0]).y tmpBlock[1].y tmpBlock[2].y tmpBlock[3].y)/4);//旋转的主要算法。可以这样分解来理解。 //先假设围绕源点旋转。然后再加上中心点的坐标for(var I=0;i4;i ){ tmpBlock[i].x=cx cy-activeBlock[i].y;tmpBlock[i].y=cy-cx活动块[i].x;} //检查旋转后方格是否合法for(var I=0;i4;i ){ if(!isCellValid(tmpBlock[i]).x,tmpBlock[i].y)){ 0返回;} } //如果合法,擦除erase();//对activeBlock重新赋值for(var I=0;i4;i ){ activeBlock[i].x=tmpBlock[i].x;activeBlock[i].y=tmpBlock[i].y;} //重画油漆();} //检查左边界,尝试着朝左边移动一个,看是否合法函数CheckLeftBorder(){ for(var I=0;iactiveblock . lengthi){ if(active block[I]).y==0){ 0返回false} if(!isCellValid(activeBlock[i]).x,activeBlock[i].y-1)){ 0返回false} }返回true} //检查右边界,尝试着朝右边移动一个,看是否合法函数CheckrightBorder(){ for(var I=0;iactiveblock . lengthi){ if(active block[I]).y==9){ 0返回false} if(!isCellValid(activeBlock[i]).x,activeBlock[i].y 1)){ 0返回false} }返回true} //检查底边界,尝试着朝下边移动一个,看是否合法函数CheckBottonBorder(){ for(var I=0;iactiveblock . lengthi){ if(active block[I]).x==17){ 0返回false} if(!isCellValid(activeBlock[i]).x 1,activeBlock[i].y)){ 0返回false} }返回true} //检查坐标为(x,y)的是否在区域种已经存在,存在说明这个方格不合法函数isCellValid(x,y){ if(x17 | | x0 | | y9 | | y0){ return false;} if(area[x][y]==1){ return false;}返回true} //擦除函数erase(){ for(var I=0;i4;i ){ tbl.rows[activeBlock[i].x].单元格[活动块[i].【y】。风格。背景颜色='白色';} } //绘活动图形函数paint(){ for(var I=0;i4;i ){ tbl.rows[activeBlock[i].x].单元格[活动块[i].y]。风格。背景颜色=' # cc 3333} } //更新区域数组函数更新区域(){ for(var I=0;i4;i ){区域[活动块]I .x][activeBlock[i].y]=1;} } //消行函数删除行(){ var line=0;for(var I=0;i18I){ var j=0;for(;j10j){ if(面积[I][j]==0){ break;} } if(j==10){ line;如果(我!=0){ for(var k=I-1;k=0;k-){ 0面积[^ 1]=面积[k];} } area[0]=generateBlankLine();} }返回线路;} //擦除整个面板函数擦除区域(){ for(var I=0;i18I){ for(var j=0;j10j ){ tbl.rows[i].单元格[j]。风格。背景颜色='白色';} } } //重绘整个面板函数油漆面积(){ for(var I=0;i18I){ for(var j=0;j10j ){ if(面积[i][j]==1){ tbl.rows[i].单元格[j]。风格。背景颜色=' # cc 3333} } } } //产生一个空白行。函数generateBlankLine(){ var line=new Array(10);for(var I=0;i10I){ line[I]=0;}返回线路;} //更新分数函数updateScore(){ document。getelementbyid(' score ').innerText=" "分数;} //键盘控制功能键keyControl(){ if(状态!=1){ return;} var code=event . key codeswitch(code){ case 37: { moveLeft();打破;} case 38: { rotate();打破;}案例39: {向右移动();打破;} case 40: { moveDown();打破;} } } //开始函数begin(e){ e . disabled=true;状态=1;TBL=文件。getelementbyid(' area ');if(!generateBlock()){ alert('游戏结束!');状态=2;返回;} paint();timer=setInterval(moveDown,1000);}文档。onkeydown=键控制;
版权声明:JavaScript实现俄罗斯方块游戏进程分析和源代码共享是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。