有一种方块游戏,像俄罗斯方块舞,但不是,名字后面有free,是什么游戏啊?

“俄罗斯方块”游戏设计电子科技大学软件学院03级02班 周银辉&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 转载请注明出处
在这之前:在这之前对“俄罗斯方块”游戏的编写尝试过两次,很不幸的是,都不理想了,原因是算法设计的不合理导致制作到中期的时候就导致某些实现显得异常复杂而夭折了,这也从侧面反映了开发方法的不合理,没有将“设计”与“生产”分开。这是第三次尝试,一个比较成功的设计,当然其也是建立在前两次失败的基础之上的。但其精彩的算法与漂亮的程序结构足以让人兴奋了。
平台说明:开发平台&&& ms.net 2003 & msWindowsXPprofessional_sp2开发语言&&& C# 1.0开发日期&&&
特殊名词说明:3.1,象素坐标(Pixel Coordinate):以显示区域所在控件的Client Rectangle的左上角为坐标原点,一个象素点为单位1的坐标
3.2,网格坐标(Gird Coordinate):如果我们将显示区域分成m×n 的网格,那么其中某一个网格所在(列,行)组成的坐标,我们称之为网格坐标,在程序中网格坐标相关项以Gird或g或G开头
3.3,块(Block):一个小格子(比如游戏中的方块图形是由小格子组成的)称为一个块,将由块来组成游戏图形
3.4,形状(Shape):游戏中的由四个小格子组成的图形称为形状
3.5,基础点(Base Point):用于指示目前形状所在位置的一个(列,行)坐标点,以网格坐标为坐标。后面将详细说明其来历。
3.6,动态方块(Dynamic Block):用于构成运动的形状的Block,共4个
设计思想:4.1,屏幕的组成:&&&& 0 ⒈⒉⒊⒋⒌⒍⒎⒏⒐& 0& □□□□□□□□□□& 1& □□□□□□□□□□& 2& □□□□□□□□□□& --------------&&&&&&&&&&&&&&&&&&&&& & 3& □□□□□□□□□□& 4& □□□□□□□□□□& 5& □□□□□□□□□□& 6& □□□□□□□□□□& 7& □□□□□□□□□□& 8& □□□□□□□□□□& 9& □□□□□□□□□□&10& □□□□□□□□□□&11& □□□□□□□□□□&12& □□□□□□□□□□&13& □□□□□□□□□□&14& □□□□□□□□□□&15& □□□□□□□□□□&16& □□□□□□□□□□&17& □□□□□□□□□□&18& □□□□□□□□□□&19& □□□□□□□□□□&20& □□□□□□□□□□&21& □□□□□□□□□□&22& □□□□□□□□□□--------------&23& ■■■■■■■■■■屏幕由23行10列的网格组成;其中0~2行:初始的形状将在这里形成然后下落,这三行用户不可见;3~22行:游戏显示区域;23行,其标记已到屏幕底部。
4.2,形状的组成:& 每一种形状都是由四个方块组成,比如■■■■由四个方块横向排列而成
4.3,形状的统一:& ■■■■等共19种形状(旋转前后的形状归为不同的形状),虽然在玩游戏时我们会去将各种不同的形状命不同的命(比如“条子”,“方块”等),但在设计游戏是它们却是统一的,它们都是“形状”。这一点是游戏成功的基础。&&&& 为了使各种不同的形状达到统一的设计,我设计了如下解决方案:将形状始终放在4×4的格子中,以该4×4格子的第一个格子为“基础点”,只要给出组成形状的四个块相对于该基础点的相对坐标,那么在基础点网格坐标的基础上就能求出各块的网格坐标。★□□□&& ★为基础点,形状各块的相对坐标是相对于这个基础点的□□□□□□□□□□□□那么■■■■在其中就如图:其四个方块相对于基础点的网格坐标就为(0,2)(1,2)(2,2)(3,2)□□□□ □□□□■■■■& □□□□& 假设基础点的网格坐标是(gX, gY),那么此形状的坐标就为(gX+0,gY+2), (gX+1,gY+2), (gX+3,gY+2), (gX+3,gY+2)我们将用一个int[8]记录下这四个相对坐标值(呵呵,用byte[8]就可以了哈)同理:□□□□□□□□■■□□■■□□& 这样,我们只要知道某个形状的相对坐标值数组,就可以轻松地求出它的各方块的排列方式,也就是其形状(样子)
4.4,移动与旋转的统一&& 从上面我们可以看出形状的移动可以这样来实现: 移动基础点的网格坐标,然后组成形状的四个方块按照其与基础点坐标的相对值而改变网格坐标,则表现为移动。&& 旋转与移动的原理一样:设旋转前的形状为A,旋转后的形状为B,组成形状A的四个方块按照B(而不是按照A)的相对于基础点坐标的相对值而改变网格坐标,则表现为旋转。比如,□□□□ □□□□■■■■& □□□□& 移动: 设其基础点网格坐标为(gX,gY),其各方块当前坐标(gX+0,gY+2), (gX+1,gY+2), (gX+3,gY+2), (gX+3,gY+2)。如果其向左移动一格,那么它的基础了坐标gX-=1; gY=gY; 其各方块移动后坐标 (gX+0,gY+2), (gX+1,gY+2), (gX+3,gY+2), (gX+3,gY+2)。旋转:设其基础点网格坐标为(gX,gY),其各方块当前坐标(gX+0,gY+2), (gX+1,gY+2), (gX+3,gY+2), (gX+3,gY+2)。如果其旋转一次,旋转后的形状如图□■□□ □■□□& □■□□□■□□那么其旋转后的各方块坐标 (gX+1,gY+0), (gX+1,gY+1), (gX+1,gY+2), (gX+1,gY+3)
如果我们将各形状编号,比如■■■■编号0,■ 编号1&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ■&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ■&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& ■那么0旋转目标为1,1的旋转目标为0所以所有形状便得到了统一,如图:&&&& 形状编号_相对坐标_旋转后的形状编号 □□□□ □□□□■■■■& 0_□□□□& □■□□ □■□□& 1_□■□□□■□□
□□□□■□□□■□□□& 2_■■□□&
□□□□□□□□■■■□& 3_■□□□
□□□□■■□□& □■□□& 4_□■□□
□□□□□□■□■■■□& 5_□□□□
□□□□□□□□■■□□■■□□& 6_
□□□□□■□□■■□□& 7_■□□□&&&
□□□□■■□□□■■□& 8_□□□□
□□□□□■□□□■□□& 9_■■□□&
□□□□■□□□■■■□& 10_□□□□
□□□□□■■□□■□□& 11_□■□□
□□□□□□□□■■■□& 12_□□■□
□□□□■□□□■■□□& 13_□■□□
□□□□□■■□& 14_■■□□□□□□
□□□□□■□□■■■□& 15_□□□□
□□□□□■□□□■■□& 16_□■□□
□□□□□□□□■■■□& 17_□■□□&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
□□□□■□□□■■□□& 18_& □■□□
数据结构5.1,网格坐标:并没有提供这样一个类或结构,但提供了网格坐标与象素坐标的转换公式:&& pCoordinate = gCoordinate*(widthOfGird+distanceOfGird);&& 象素坐标值 = 网格坐标值×(网格边长+网格间距)
5.2,网格点(GirdPoint):一个结构,它表示一个以网格坐标为坐标的点public struct GirdPoint{&&public int X;&&public int Y;&&&&&&& //…各种构造函数}
5.3,块(Block):继承于System.Windows.Forms.Label,用它来生成组成形状的块对象public class Block: System.Windows.Forms.Label{&&private GirdPoint gL// 网格坐标&&//获取或设置 网格坐标值(若设置,那么其象素坐标会自动变化为相应值)&&&&&&&& public GirdPoint GLocation&&&& {&&&get&&&{&&&&return this.gL&&&}&&&set&&&{&&&&this.gLocation =&&&&&&&&&&&&&&&&&& //其中Globals.ToPcoordinate()是一个将网格坐标值转换成象素坐标值的函数&&&&this.Location = new Point( Globals.ToPCoordinate(this.gLocation.X),&&&&&Globals.ToPCoordinate(this.gLocation.Y));&&&}&&}&&&&&&& //……(各种构造函数)}对块位置的操作只需要指定其网格坐标,其象素坐标会自动变化为相应值
5.4,形状(Shape):一个结构,由它保存游戏中的形状的相关信息public struct Shape{&& //获取或设置该形状的索引值&& public int I&& //获取或设置一个数组,其为该形状的相对于基础点的相对网格坐标组&& public int[] DC& // 获取或设置该形状旋转后的新形状的索引&& public int EddiedI&& public Shape(int index, int[] dCoordinates, int eddiedIndex)&& {&&&&&& this.Index =&&&&&& this.DCoordinates = dC&&&&& this.EddiedIndex = eddiedI}
5.5,背景方块数组(BackBlocks):一个Block[,],其维持着23行10列的Block对象,这些对象将作为屏幕的背景,当下落的形状下落到底部时,形状所在位置的背景方块将被点亮,这表现为下落的形状被固定住了
5.6,网格数组(GirdArray):一个int[,],其维持着整个屏幕的背景方块的状态,当该数组中的某个元素值由0变为1时,表示在屏幕中的该位置被某个方块占据,当由1变为0是,表示在屏幕中的该位置被释放而未被占据。被占据表现为屏幕上该位置已经有方块了。
5.7,动态方块数组(DynamicBlocksArray):一个Block[4],其维持着四个Block对象,游戏中的任何运动的形状都是由这四个Block对象变化位置而得到的
5.8,预览网格数组(ViewGirdArray):一个int[,],于GirdArray一样,只不过它维持着屏幕旁边的用于预览下一个即将出项的形状的小屏幕
5.9,预览方块数组(ViewDynamicBlocksArray):一个Block[4],其维持着四个Block对象,游戏中屏幕普遍的小屏幕显示了下一个即将出现的形状,而这个预览形状便是由这四个Block对象变化位置而得到的
5.10,Shapes:一个Shape[19],它维持着游戏中的19个形状&&& public static readonly Shape[] Shapes = new Shape[19]&&&{&&&&new Shape(0,new int[8]{0,2,1,2,2,2,3,2},1),&&&&new Shape(1,new int[8]{1,0,1,1,1,2,1,3},0),&&&&new Shape(2,new int[8]{0,0,0,1,0,2,1,2},3),&&&&new Shape(3,new int[8]{0,2,1,2,2,2,0,3},4),&&&&new Shape(4,new int[8]{0,1,1,1,1,2,1,3},5),&&&&new Shape(5,new int[8]{2,1,0,2,1,2,2,2},2),&&&&new Shape(6,new int[8]{0,2,1,2,0,3,1,3},6),&&&&new Shape(7,new int[8]{1,1,0,2,1,2,0,3},8),&&&&new Shape(8,new int[8]{0,1,1,1,1,2,2,2},7),&&&&new Shape(9,new int[8]{1,1,1,2,0,3,1,3},10),&&&&new Shape(10,new int[8]{0,1,0,2,1,2,2,2},11),&&&&new Shape(11,new int[8]{1,1,2,1,1,2,1,3},12),&&&&new Shape(12,new int[8]{0,2,1,2,2,2,2,3},9),&&&&new Shape(13,new int[8]{0,1,0,2,1,2,1,3},14),&&&&new Shape(14,new int[8]{1,1,2,1,0,2,1,2},13),&&&&new Shape(15,new int[8]{1,1,0,2,1,2,2,2},16),&&&&new Shape(16,new int[8]{1,1,1,2,2,2,1,3},17),&&&&new Shape(17,new int[8]{0,2,1,2,2,2,1,3},18),&&&&&&&&&& new Shape(18,new int[8]{1,1,0,2,1,2,1,3},15),&&&&&&&&&&&&& }
功能的实现:6.1,形状的生成:随机生成形状编号,并根据该编号生成相应的形状&& 设形状编号为indexOfShape,组成形状的四个动态方块已存在DynamicBlockArray中,基础点为BasePoint,所有形状已存在Shapes中void AssembleShape(int indexOfShape){&//重新安排四个动态块的位置以形成新形状&& DynamicBlocksArray[0].GLocation = new GirdPoint(&&&&&&&&&&&&&&&&& Shapes[indexOfShape].DCoordinates[0] + BasePoint.X,&&&&&&&&&&&&&& Shapes[indexOfShape].DCoordinates[1]+ BasePoint.Y);
&& DynamicBlocksArray[1].GLocation = new GirdPoint(&&&&Shapes[indexOfShape].DCoordinates[2] + asePoint.X,&&&&&&&&&&&&&& Shapes[indexOfShape].DCoordinates[3]+ BasePoint.Y);
&& DynamicBlocksArray[2].GLocation = new GirdPoint(&&&&&&&&&&&&& Shapes[indexOfShape].DCoordinates[4] + BasePoint.X,&&&&&&&&&&&&& Shapes[indexOfShape].DCoordinates[5] + BasePoint.Y);
&& DynamicBlocksArray[3].GLocation = new GirdPoint(&&&&&& Shapes[indexOfShape].DCoordinates[6] + BasePoint.X,&&&&&&& Shapes[indexOfShape].DCoordinates[7] + BasePoint.Y);}
6.2,形状的移动,先试探能否向指定方向移动如果能,那么移动,否则不移动。试探,由于左右下三个方向移动的本质是一样的,所以它们可以由统一的函数来实现。移动,则是通过移动基础点位置,然后根据基础点位置重新安排一下四个动态方块的位置来实现,即,移动基础点,然后调用一次上面的AssembleShape函数。&&&& 试探:设当前形状编号为indexOfShape,arg参数指定要试探的方向 ’L’,’R’,’D’ 分别为左,右,下;基础点为BascPoint,所有形状已存再Shapes中,CountOfTier为屏幕网格的列数。取得其试探位置的网格坐标,如果该位置已经超出屏幕或该位置已经被其他方块占据,则试探的位置不可达,如果组成形状的四个方块中有一个方块的试探位置不可达,那么试探函数返回false,说明不可向指定方向移动private static bool canMove(int indexOfShape, char arg){&try&{&&&& GirdPoint tempBaseP
&&&& switch(arg)&&{&&&case 'L':&&&&&& tempBasePoint = new GirdPoint(BasePoint.X-1,BasePoint.Y);&&&&&&&&case 'R':&&&&&& tempBasePoint = new GirdPoint(BasePoint.X+1, BasePoint.Y);&&&&&&&&case 'D':&&&&tempBasePoint = new GirdPoint(BasePoint.X, BasePoint.Y+1);&&&&&&&&&&&&&& case 'E'://不移动,用于判断能否旋转,&&&&&&&&&&&&&&&&&&&&&& //与判断移动不同的是传入的indexOfShape,&&&&&&&&&&&&&&&&&&&&&& //判断旋转用的是旋转后的形状的索引,而移动用的是当前的&&&&&&&&&&&&&&&&&&& tempBasePoint = BaseP&&&&&&&&&&&&&&&&&&&&default:&&&&MessageBox.Show("错误的参数"+arg+"\n应该为'L'或'R'或'D'");&&&&&&}&&&&&&int gX0 = Shapes[indexOfShape].DCoordinates[0]+tempBasePoint.X;&&int gY0 = Shapes[indexOfShape].DCoordinates[1]+tempBasePoint.Y;&&int i =& GirdArray[gY0,gX0];&&&&&&&&&&&& &&int gX1 = Shapes[indexOfShape].DCoordinates[2]+tempBasePoint.X;&&int gY1 = Shapes[indexOfShape].DCoordinates[3]+tempBasePoint.Y;&&int j = GirdArray[gY1,gX1];
&&int gX2 = Shapes[indexOfShape].DCoordinates[4]+tempBasePoint.X;&&int gY2 = Shapes[indexOfShape].DCoordinates[5]+tempBasePoint.Y;&&int m = GirdArray[gY2,gX2];
&&int gX3 = Shapes[indexOfShape].DCoordinates[6]+tempBasePoint.X;&&int gY3 = Shapes[indexOfShape].DCoordinates[7]+tempBasePoint.Y;&&int n = GirdArray[gY3,gX3];
&&//i,j,m,n为其即将到达的新位置的网格值,若为1,说明该网格已被占据&&&&if(gX0&0 || gX0&= CountOfTier ||& i == 1 ||&&&&&& gX1&0 || gX1&= CountOfTier || j == 1 ||&&&gX2&0 || gX2&=& CountOfTier || m == 1 ||&&&gX3&0 || gX3&= CountOfTier || n == 1)&&{&&&&&}&&&&& }&&& catch&&& {&&&&&&& }
&&&}&&&& 移动:移动基础点,并重新组成形状,比如左移,void ToLeft(int indexOfShape){&&& if(canMove(indexOfShape,’L’)&&& {&&BasePoint = new GirdPoint(BasePoint.X-1, BasePoint.Y);&&AssembleShape(indexOfShape);&&& }}
6.3,自动下落,设一个计时器timer,其每隔一定时间调用一次ToDown函数void ToDown(int indexOfShape){&&& if(canMove(indexOfShape,’D’)&&& {&&BasePoint = new GirdPoint(BasePoint.X, BasePoint.Y+1);&&AssembleShape(indexOfShape);&&& }&&& else&&& {&&&&&&& //其他,比如固定下落的形状,判断得分,判断游戏是否已经结束等等&&& }}
6.4,下落形状的固定,当试探到不能下落时,就固定住当前形状。其实组成形状的四个块并没有被固定住,而是当它们当前位置对应的四个背景方块被点亮后,它们离开了当前位置而到屏幕的顶部(0~2行,不可见)组合新形状去了。对应的四个背景方块被点亮表现为形状被固定void FixShape(){&for(int i=0; i&4; i++)&{&&&&&&& //将该位置的背景方块点亮(变为指定的颜色,假设为ColorOfFixedBlock)&&&&&& BackBlocks[DynamicBlocksArray[i].GLocation.Y,& &&&&&&&&&&&&&&&& DynamicBlocksArray[i].GLocation.X].BackColor = ColorOfFixedB &&&&&&& //将对应的网格值设置为1,表示此网格已经被占据&&&&&& GirdArray[DynamicBlocksArray[i].GLocation.Y, DynamicBlocksArray[i].GLocation.X] = 1&&&& }&&& //其他,比如判断是否应该消行加分等&&& //将基础点移动到顶部,并产生新形状等等}
6.5,旋转,与移动的原理一样。先试探能否旋转,如果能的话,取得旋转后的形状的索引,并按照此索引调用函数AssembleShape()。&&& 试探能否旋转:很巧妙地运用了试探能否移动的CanMove函数。与移动不同的是,试探能否旋转传入的是旋转后的形状的索引bool CanEddy(indexOfShape)&&& {&&&&&& int eddiedIndex = AllShapes.Shapes[indexOfShape].EddiedI//旋转后的新形状的索引&&&&&& return canMove(eddiedIndex,’E’);&&& }&& 旋转:很巧妙地运用了移动时的AssembleShape()&& void Eddy(indexOfShape)&& {&&&&&& if(CanEddy(indexOfShape)&&&&&& {&&&&&&&&& int eddiedIndex = AllShapes.Shapes[indexOfShape].EddiedI//旋转后的新形状的索引&&&&&&&&& AssembleShape(eddiedIndex);&&&&&& }&& }这是激动人心的,程序巧妙地将左移、右移、下移、旋转高度地统一了起来,它们的实质都是调用CanMove()函数进行判断,然后再调用AssembelShape()函数移动四个动态方块的位置,而表现出各种效果。多么棒的设计啊(呵呵,自我欣赏了)
6.6,消行,当形状被固定后需要判断是否有满行,如果有,则消去已满的行&&& 扫描是否存在满行:没有必要扫描整个屏幕,而只需要扫描当前被固定的形状的基础点一下的四行(但不能超过第22行,因为第23行始终是满的)。对于某一行而言,如果该行的GirdArray对应值均为1,说明该行已被全部占据(或者说,如果该行的GirdArray对应值至少有一个为1,说明该行没有被全部占据),那么应该消去该行&&& void ScanFullLines(int lineStart,int lineEnd)&&& {&&&&&&&&& int countOfFullLine = 0;//记录此次消除的行数,以便加分
&&&&&& for(int i= lineS i&=lineE i++)&&&&&& {&&&bool isFull =//指示是否已被填满&&&for(int j=0; j&CountOfT j++)//countOfTier:屏幕列数&&&{&&&&if(GirdArray[i,j]==0)&&&&{&&&&&isFull =&&&&}&&&}
&&&if(isFull)&&&{&&&&countOfFullLine++;&&&&DelLine(i);//消去第i行&&&&&&&&& }&&&&&&switch(countOfFullLine)&&&&&&&&&&&&& {&&&&&&&&&&&&&&&& //根据所消行数加分&&&&&&&&&&&&& }&&&&&& 消去指定行:将该行上的背景方块熄灭(与点亮相反,变为另一种颜色,设为ColorOfBackBlock),并将该行以上的所有方块都下移一格。设背景方块数组为BackBlocks,网格数组为GirdArrayvoid DelLine(int indexOfLine){ &//熄灭该行上的背景块,表现为移出了该行上的块&for(int i=0; i&CountOfT i++)&{&&&&&&&& //熄灭对应的背景方块&&BackBlocks[indexOfLine,i].BackColor = ColorOfBackB&&//释放被占据的网格&&GirdArray[indexOfLine,i] = 0;&&&& }&//该行以上的所有行整体下落&for(int i=indexOfLine-1;i&=3; i--)&{&&for(int j=0; j&CountOfT j++)&&{&&&if(GirdArray[i,j] == 1)&&&{&&&&//此块熄灭,其正下方的块点亮,表现为下落了一格&&&&GirdArray[i,j] = 0;&&&&BackBlocks[i,j].BackColor =.ColorOfBackB&&&&GirdArray[i+1,j] = 1;&&&&BackBlocks[i+1,j].BackColor = ColorOfFixedB&&&}&&& }&&& }& }
6.7 游戏存档,当用户欲保存当前游戏以供以后继续时,使用这个功能。需要保存的数据有:目前的速度级别,目前的分数,目前的已屏幕上已被固定的各形状。存档文件仅需要一百多个字节就可以了,是这样做的:第一行写入游戏速度级别,第二行写入游戏分数,从第三行开始写入游戏中网格数组(GirdArray),网格数组中为1的对应的背景方块数组的方块即是被固定的(点亮的)。bool SaveGame(string fileName){&try&{&&&&&&&&& StreamWriter sWriter = &&&&&&&&&&&&&&&&& new StreamWriter(fileName,false,System.Text.Encoding.Default, 100);
&&//写入速度级别&&sWriter.WriteLine(SpeedLevel.ToString());
&&//写入分数&&sWriter.WriteLine(Score.ToString());
&&//写入背景网格状态&&for(int i=0; i&CountOfR i++)&&{&&&for(int j=0; j& CountOfT j++)&&&{&&&&sWriter.Write(GirdArray[i,j].ToString());&&&}&&}
&&sWriter.Close();&}&catch(Exception ex)&{&&MessageBox.Show("未能保存!\n原因是:\n"+ex.Message);&&&}
&&&}比如我的一个游戏存档如下:115001111
6.8 加载游戏存档,将游戏存档读出,并将游戏中的各变量更改为存档中的值就可以了。&&&&&& bool LoadGame(string fileName)&&&&&& {&&&try&&&{&&&&StreamReader sReader =&&&&&new StreamReader(fileName,System.Text.Encoding.Default,false,100);
&&&&&&&&&&&&&&&&& //加载游戏速度&&&&string strSpeedLevel = sReader.ReadLine();&&&&Level = int.Parse(strSpeedLevel));
&&&&//加载游戏分数&&&&string strScore = sReader.ReadLine();&&&&Score = int.Parse(strScore);&&&&&&&&//加载游戏网格状态&&&&char[] buffer = new char[1];&&&&for(int i=0; i&CountOfR i++)&&&&{&&&&&for(int j=0; j&CountOfT j++)&&&&&{&&&&&&sReader.Read(buffer,0,1);&&&&&&GirdArray[i,j] = int.Parse(buffer[0].ToString());&&&&&&&&&&&&&&&&&&&&&&&&&& //如果对应值为1,则点亮对应的背景网格&&&&&&if(GirdArray[i,j]==1)&&&&&&{&&&&&&&BackBlocks[i,j].BackColor = ColorOfFixedB&&&&&&}&&&&&&else&&&&&&{&&&&&&&BackBlocks[i,j].BackColor = ColorOfBackB&&&&&&}&&&&&}&&&&}
&&&&sReader.Close();&&&}&&&catch(Exception ex)&&&{&&&&MessageBox.Show("加载游戏失败\n原因是:\n"+ex.Message);&&&&&&&}
阅读(...) 评论() &俄罗斯方块小游戏(俄罗斯方块大全)
游戏简介:最好玩的俄罗斯方块小游戏、俄罗斯方块游戏,尽在新浪玩玩小游戏平台。这里不仅有俄罗斯方块大全,还有数以千计、五花八门的免费在线小游戏等你来玩,还等什么!快来玩吧!
俄罗斯方块小游戏
人气用户推荐
热门游戏榜
新浪玩玩意见反馈
欢迎使用新浪玩玩并提出宝贵建议。请提交玩玩意见反馈。
Copyright & 1996 - 2016 SINA Corporation, All Rights Reserved
北京市通信公司提供网络带宽当前位置:正文
微信扫一扫分享到朋友圈
近期「长得像」俄罗斯方块的益智游戏层出不穷,99 Bricks Wizard Academy 就是其中之一。这款游戏虽是以俄罗斯方块作为主要元素,但玩法上并不是大家所熟知的排消机制,而是利用彩色方块叠建高塔,玩起来别具新意,十分有趣。游戏时,玩家必须试图利用「L」「I」方块建造好塔的根基。左右划屏调整方块,将其放置在较为「安稳」的位置,让塔不会因为无法平衡而倒塌。游戏中你会发现每一块方块都有其重量,如果受力不平衡,方块便会倾斜掉落,超过三块游戏结束!方块堆叠的高度越高,达到「魔法线」便可激活新的方块技能提升自己的建塔能力,如:方块凝固、巨大化等。而游戏中的「闪电魔法」机制,也可帮助我们消除「杂乱」的方块,保证高塔的平衡。随着游戏的深入,还会出现反派巫师前来捣乱,阻碍玩家的建塔进程,增添游戏的挑战难度。
分享给好友
分享到微信朋友圈:
第一步 打开微信底部扫一扫
第二步 扫下面的文章二维码
第三步 右上角点击转发
相关文章Relevant
1.哪里有这样的教练,请!叫!上!我!2.做陶瓷真的是一件很邪恶的事,甩得少妇心花怒放.3.妈蛋,脱出去砍了!!4.国外的军训我...
来自德国的摄影师Julius Ise为某棒棒糖拍摄了一组可以称得上是史上最性感的棒棒糖广告,这组作品名为《leck mich》,意为“舔我”...
年初去日本考察美术馆,趁便在东京与徐富造先生聚会,他说不巧,高仓在北海道拍戏,这次见不成了.转眼年底,高仓健走了,我即...
点击题目下方魅力女人,一键关注本账号委内瑞拉这个国家,还有个别称,叫“选美之都”,也可以叫“Miss Factory选美小姐工厂”...
手机完全侵入我们的生活,不管你身在何处,总能见到神态各异的人在划!手!机!过人行横道也在划!手!机!跟朋友出去吃饭还是...
感知CG,感触创意,感受艺术,感悟心灵 国外百年前的绘本和现如今的实景,今昔相比,历史的尘埃犹在.∨今昔相比来源:互联网...}

我要回帖

更多关于 俄罗斯方块单机版下载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信