俄罗斯方块编写思路及源码

 

俄罗斯方块编写思路及源码

  

    顾名思义,俄罗斯方块自然是俄罗斯人发明的。这位牛人叫做阿列克谢·帕基特诺夫(Alexey Pazhitnov) 。

  俄罗斯方块的基本规则:
  1、一个用于摆放小型正方形的平面虚拟场地,其标准大小:行宽为10,列高为20,以每个小正方形为单位;
  2、一组由4个小型正方形组成的规则图形,共有7种,分别以S、Z、L、J、I、O、T这7个字母的形状来命名;
  3、随机地输出方块到场地顶部,以一定的规则进行移动、旋转、下落和摆放,锁定并填充到场地中。每次摆放如果将场地的一行或多行完全填满,则组成这些行的所有小正方形将被消除,并且以此来换取一定的积分。而未被消除的方块会一直累积,并对后来的方块摆放造成各种影响。
  4、方块移到区域最下方或是落到其他方块上无法移动时,就会固定在该处。如果未被消除的方块堆放的高度超过场地所规定的最大高度,则游戏结束。

  
  下面我简单说一下我的思路,理解下面几点会比较清楚一些。

  1,基础:你首先要能画出一个带颜色的方块。举一反三:可以画一个就可以画4个了。(TC中画方块用到了EGAVGA.BGI这个文件)
  2,移动:一个方块消失,相邻地方一个方块出现,在视觉上就是移动了。
  3,消失:用背景颜色在同样的地方画同样大小的方块。
  4,俄罗斯方块:由四个方块组成,方块互相邻接。共有7种俄罗斯方块(S、Z、L、J、I、O、T)。
  5,每种俄罗斯方块,又可以旋转,以90度旋转,则每种就有4个旋转的状态。
  6,相对坐标:视觉上像素这个单位太小,用方块的大小作为相对坐标的单位。
  7,随机产生:使用伪随机函数,参数一般用上系统当前时间,你再随意捏造个四则运算,就会产生出独一无二的随机数了。随机数用于产生新的俄罗斯方块的种类,以及旋转的状态。
  8,按键分四种:上、下、左、右。上键:旋转当前的俄罗斯方块;下键:快速下降到底;左键:左移一格;右键:右移一格。
  9,旋转:默认按顺时钟旋转。这里用到了一个坐标的转换,当方块旋转时,横坐标与纵坐标要互换,我这里是把数学中的坐标转换公式应用进来了,这是这个游戏中最有难度的部分了。
  10,一行填满:一行里面,填充满小方块,此时需要进行记分,并消掉这一行。
  11,记分:每消掉一行,进行记分;若同时消掉多行,记分要更多。--这是鼓励一次消多行。
  12,结束条件:方块填充到了顶部。

  也就这么多,理解了这些,整个框架也就出来了。

 

 

源代码如下:

 

#include <graphics.h>
#include <stdio.h>
#include <stdlib.h>

char x,y;/*当前操作的俄罗斯方块的坐标,实际以一个俄罗斯方块的左上角的小方块的坐标表示*/
char str[16];
char num_line_full=0,num_line_old=0;/*消掉的行数,用于计分*/
char type_cur,type_new;/*俄罗斯方块共有7种,以变量type_cur表示*/
char block_status;/*无论如何转动,只有四种状态。以变量block_status来表示。*/
char screen[10][29]={0};/*表示画面内的各个格是否填充。  画面大小:横向可以放下10个方块,纵向可以放下29个方块 */
char block_unit[4][2]={0};/*表示一个俄罗斯方块,其中有4个小方块,每个小方块有坐标(x,y) */
int score1=0,speed=1000;/*speed其实是个延迟时间,可根据CPU的速度调整。更好的方式是使用别的方式进行延时*/

void draw_unit(char,char,char);  /* 画一个小方块  */         
void dl(int); /* 进行延时  */ 
void draw_block(char);  /* 画一个俄罗斯方块  */                 
void set_block_pos(char,char);/*给一个俄罗斯方块的位置赋值*/
void up(void);  /* 按下上键后的操作  */                        
void down(void);/* 按下下键后的操作  */   
void left(void);/* 按下左键后的操作  */                        
void right(void);/* 按下右键后的操作  */   
char rotate_x(char,char,char);    /* x 坐标旋转*/        
char rotate_y(char,char,char);/* y 坐标旋转*/
char max1(char,char,char);  /*取最大值*/      
char min1(char,char,char);/*取最小值*/
void score(void);/* 计算并显示得分  */                   
void process_full_line(void);/*处理填满小方块的行*/
void save(void);/* 保存最高分值  */


main()
{
     char cycy=0,i,j,b,ci;
     initgraph(VGA,VGAHI,"c://tc//egavga.bgi");/*图形模式初始化*/
     getch();

     setfillstyle(1,7);/*设置填充模式*/
     setcolor(7);/*设置颜色*/
     bar(200,10,350,430);/*按设置的模式,画一个长方形*/
     setcolor(15);rectangle(198,8,352,432);
 x=4;type_cur=0;block_status=0;y=1;
 do
 {
   set_block_pos(type_cur,block_status);/*进行位置赋值*/
   draw_block(14);/*画出*/
   score();/*记分*/
   for(ci=0;ci<10;ci++)/*下降一格的时间里面,提供10次机会,判断是否有按键,并进行相应处理*/
   {
     if(kbhit()!=0)
       b=getch();/*获取按键值*/
     else
       b=0;

     if(b==13)
      break;
     switch(b)
     {
                  case 72: up();    break;/*上键处理*/
                  case 75: left();  break;/*左键处理*/
                  case 77: right(); break;/*右键处理*/
                  case 80: down();  break;/*下键处理*/
      }
      dl(speed/2);/*通过延时控制速度*/
   }

   j=max1(block_unit[3][1],block_unit[1][1],block_unit[2][1]);
  if((j>=27)||(screen[block_unit[0][0]][block_unit[0][1]+1]+screen[block_unit[1][0]][block_unit[1][1]+1]+screen[block_unit[2][0]][block_unit[2][1]+1]+screen[block_unit[3][0]][block_unit[3][1]+1]>=1))/*已经触底*/
  {
   screen[block_unit[0][0]][block_unit[0][1]]=1;screen[block_unit[1][0]][block_unit[1][1]]=1;
   screen[block_unit[2][0]][block_unit[2][1]]=1;screen[block_unit[3][0]][block_unit[3][1]]=1;
   y=2;
   x=5;
  
   do/*随机产生一个新的俄罗斯方块,其形状与上一个不同*/
   {
    randomize();          
    type_new=random(100);
    type_new%=7;
    if(type_new==0)
      type_new=7;
   }
   while(type_cur==type_new);

   type_cur=type_new;
   j=0;
   process_full_line();/*判断是否能消一行*/
  }
  else/*未触底,继续下降*/
  {
     draw_block(0);/*在原位置消失--准备更新位置,再画出*/
     y++;
   }
   for(i=0;i<10;i++)/*在已经经过下降一格的时间之后,判断在顶部是否有块存在,若存在,则game over*/
     if(screen[i][0]==1)
     {
      cycy=1;
      getch();
      break;
     }

  if(cycy==1)
  {
   cycy=0;
   break;
  }
 }
 while(b!=13);

 getch();
 closegraph();/* 关闭图形模式 */
 save();/* 若创造新记录,保存分值 */
 getch();
}

void draw_unit(char x,char y,char color)/* 画一个小方块  */
{
 setfillstyle(1,color);
 setcolor(color);
 bar(200+x*15,10+y*15,200+(x+1)*15-2,10+(y+1)*15-2);
}

void draw_block(char color)/* 画一个俄罗斯方块  */
{
 char i,t;
 for(i=0;i<4;i++)
    draw_unit(block_unit[i][0],block_unit[i][1],color);
}

void dl(int a)/* 进行延时 ,更好的方式是使用别的方式进行延时,避免完全占用cpu */
{
 int r,n;
 for(r=0;r<a;r++)
  for(n=0;n<30000;n++)
  {
   n++;
   n--;
  }
}

char rotate_x(char x0,char y0,char n)/* x 坐标旋转*/
{
 char x1,x2,y1,y2;
 x1=y0+x-y;   
 y1=x+y-x0;
 if(n==0)
    return(x0);
 if(n==1)
    return(x1);
 if(n>=2)
 {
  x2=y1+x-y; 
  y2=x+y-x1;
  if(n==2)
     return(x2);
  else
  {
   x1=y2+x-y;
   y1=x+y-x2;
   if(n==3)
      return(x1);
  }
 }
}

char rotate_y(char x0,char y0,char n)/* y 坐标旋转*/
{
 char x1,x2,y1,y2;
 x1=y0+x-y;   
 y1=x+y-x0;
 if(n==0)
    return(y0);
 if(n==1)
  return(y1);
 if(n>=2)
 {
  x2=y1+x-y; 
  y2=x+y-x1;
  if(n==2)
     return(y2);
  else
  {
   x1=y2+x-y;
   y1=x+y-x2;
   if(n==3)
      return(y1);
  }
 }
}

void left()/* 按下左键后的操作  */
{
 char j;
 set_block_pos(type_cur,block_status);
 draw_block(0);/*原位置去掉*/
 j=min1(block_unit[3][0],block_unit[1][0],block_unit[2][0]);
 if((j>=1)&&(screen[block_unit[0][0]-1][block_unit[0][1]]==0)&&(screen[block_unit[1][0]-1][block_unit[1][1]]==0)&&(screen[block_unit[2][0]-1][block_unit[2][1]]==0)&&(screen[block_unit[3][0]-1]

[block_unit[3][1]]==0))
 {
  j--;
  x--;
 }

 set_block_pos(type_cur,block_status);
 draw_block(14);/*新位置画出*/
}

void right()/* 按下右键后的操作  */ 
{
 char j;
 set_block_pos(type_cur,block_status);
 draw_block(0);/*原位置去掉*/
 j=max1(block_unit[3][0],block_unit[1][0],block_unit[2][0]);
 if((j<9)&&(screen[block_unit[0][0]+1][block_unit[0][1]]==0)&&(screen[block_unit[1][0]+1][block_unit[1][1]]==0)&&(screen[block_unit[2][0]+1][block_unit[2][1]]==0)&&(screen[block_unit[3][0]+1]

[block_unit[3][1]]==0))
 {
  j++;
  x++;
 }

 set_block_pos(type_cur,block_status);
 draw_block(14);/*新位置画出*/
}

void set_block_pos(char n,char block_status)/* 给一个俄罗斯方块赋值,含4个块,每个块的坐标(x,y)*/
{    
 block_unit[0][0]=x;
 block_unit[0][1]=y;
 n=n%7;
 if(n==0)
    n=7;
        block_status=block_status%4;
 switch (n)
 {
  case 1: block_unit[1][0]=rotate_x(x-1,y,block_status);block_unit[1][1]=rotate_y(x-1,y,block_status);
     block_unit[2][0]=rotate_x(x,y+1,block_status);block_unit[2][1]=rotate_y(x,y+1,block_status);
     block_unit[3][0]=rotate_x(x,y+2,block_status);block_unit[3][1]=rotate_y(x,y+2,block_status);
    break;
  case 2:     block_unit[1][0]=rotate_x(x-1,y,block_status);block_unit[1][1]=rotate_y(x-1,y,block_status);
     block_unit[2][0]=rotate_x(x,y-1,block_status);block_unit[2][1]=rotate_y(x,y-1,block_status);
     block_unit[3][0]=rotate_x(x,y-2,block_status);block_unit[3][1]=rotate_y(x,y-2,block_status);
    break;
  case 3:     block_unit[1][0]=rotate_x(x-1,y-1,block_status);block_unit[1][1]=rotate_y(x-1,y-1,block_status);
     block_unit[2][0]=rotate_x(x,y+1,block_status);block_unit[2][1]=rotate_y(x,y+1,block_status);
     block_unit[3][0]=rotate_x(x-1,y,block_status);block_unit[3][1]=rotate_y(x-1,y,block_status);
    break;
  case 4:     block_unit[1][0]=rotate_x(x-1,y,block_status);block_unit[1][1]=rotate_y(x-1,y,block_status);
     block_unit[2][0]=rotate_x(x-1,y+1,block_status);block_unit[2][1]=rotate_y(x-1,y+1,block_status);
     block_unit[3][0]=rotate_x(x,y-1,block_status);block_unit[3][1]=rotate_y(x,y-1,block_status);
    break;
  case 5:     block_unit[1][0]=rotate_x(x-1,y,block_status);block_unit[1][1]=rotate_y(x-1,y,block_status);
     block_unit[2][0]=rotate_x(x,y-1,block_status);block_unit[2][1]=rotate_y(x,y-1,block_status);
     block_unit[3][0]=rotate_x(x,y+1,block_status);block_unit[3][1]=rotate_y(x,y+1,block_status);
    break;
  case 6:     block_unit[1][0]=rotate_x(x,y+1,block_status);block_unit[1][1]=rotate_y(x,y+1,block_status);
     block_unit[2][0]=rotate_x(x,y-1,block_status);block_unit[2][1]=rotate_y(x,y-1,block_status);
     block_unit[3][0]=rotate_x(x,y-2,block_status);block_unit[3][1]=rotate_y(x,y-2,block_status);
    break;
  case 7:     block_unit[1][0]=rotate_x(x-1,y,block_status);block_unit[1][1]=rotate_y(x-1,y,block_status);
     block_unit[2][0]=rotate_x(x,y-1,block_status);block_unit[2][1]=rotate_y(x,y-1,block_status);
     block_unit[3][0]=rotate_x(x-1,y-1,block_status);block_unit[3][1]=rotate_y(x-1,y-1,block_status);
    break;
 }
}

void up()/* 按下上键后的操作  */
{
 char j,k;
 set_block_pos(type_cur,block_status);
 draw_block(0);
 block_status++;
 block_status=block_status%4;
 set_block_pos(type_cur,block_status);
 j=min1(block_unit[3][0],block_unit[1][0],block_unit[2][0]);
 k=max1(block_unit[3][0],block_unit[1][0],block_unit[2][0]);
 if((k<=9)&&(j>=0))
 {
  if((screen[block_unit[0][0]][block_unit[0][1]]==0)&&(screen[block_unit[1][0]][block_unit[1][1]]==0)&&(screen[block_unit[2][0]][block_unit[2][1]]==0)&&(screen[block_unit[3][0]][block_unit[3][1]]==0))
   draw_block(14);      /* not overlap */
  else
  {            
   block_status+=3;    
   block_status%=4;
   set_block_pos(type_cur,block_status);
   draw_block(14);
  }
 }
 else
 {
  block_status+=3;    
  block_status%=4;
  set_block_pos(type_cur,block_status);
  draw_block(14);
 }
}

void down(void)/* 按下下键后的操作  */  
{
 char j,cy=0;
 set_block_pos(type_cur,block_status);
 draw_block(0);
 j=max1(block_unit[3][1],block_unit[2][1],block_unit[1][1]);

 while(j<28)
 {    
  j=max1(block_unit[3][1],block_unit[1][1],block_unit[2][1]);
  if((j>=27)||(screen[block_unit[0][0]][block_unit[0][1]+1]==1)||(screen[block_unit[1][0]][block_unit[1][1]+1]==1)||(screen[block_unit[2][0]][block_unit[2][1]+1]==1)||(screen[block_unit[3][0]][block_unit[3][1]+1]==1))
  {
   screen[block_unit[0][0]][block_unit[0][1]]=1;
   screen[block_unit[1][0]][block_unit[1][1]]=1;
     screen[block_unit[2][0]][block_unit[2][1]]=1;
   screen[block_unit[3][0]][block_unit[3][1]]=1;
     draw_block(14);   /* avoid block disappeared */
     process_full_line();
   y=2;
   x=5;
   do
   {
       randomize();          
    type_new=random(100);
       type_new%=7;
       if(type_new==0)
      type_new=7;
   }
   while(type_new==type_cur);        /* avoid the same block appear continually */

   type_cur=type_new;

   j=0;
   set_block_pos(type_cur,block_status);
   draw_block(14);
   cy=1;
  }
  else
  {
   dl(speed/4);
     set_block_pos(type_cur,block_status);
     draw_block(0);
     y++;
  }
  if(cy==1)
  {
   cy=0;
   break;
  }
  set_block_pos(type_cur,block_status);
  draw_block(14);
 }
}

void process_full_line(void)/*消掉一行*/
{
 char jj,y1,r,x1,y2;
 for(jj=0;jj<4;jj++)/*分别判断四个小方块---似乎不需要??下面已经是整屏幕判断了*/
 {
  for(y1=27;y1>0;y1--)/*从底下判断到顶上。*/
  {
   r=0;
   for(x1=0;x1<10;x1++)/*对于每一行,从左判断到右*/
   {
    if(screen[x1][y1]==1)/*统计已经填充的小方块的个数*/
        r++;
   }
   if(r==10)/*一行已经填满了*/
   {
    num_line_full++;
    for(x1=0;x1<10;x1++)
    {
     draw_unit(x1,y1,0);/*使该行消失*/
     screen[x1][y1]=0;/*清标志*/
    }

    for(y2=y1-1;y2>0;y2--)/*上面的所有块,整体下移一行*/
    {
     for(x1=0;x1<10;x1++)
     {
      if(screen[x1][y2]==1)
      {
       screen[x1][y2]=0;
       draw_unit(x1,y2,0);
       draw_unit(x1,y2+1,14);
       screen[x1][y2+1]=1;
      }
     }
    }
   }
  }
 }
}

char max1(char a,char b,char c)/*取最大值*/  
{
 char max3;
 if(a>=b)
           max3=a;
 else
           max3=b;

        if(max3<c)
           max3=c;

        return(max3);
  }

char min1(char a,char b,char c)/*取最小值*/
{
 char min;
 if(a<=b)
    min=a;
 else
    min=b;
 
 if(min>c)
    min=c;

 return(min);
  }

void score(void)/* 计算并显示得分  */
{
 char a,b=1;
 setcolor(0);
 outtextxy(20,20,str);
 setcolor(14);
 for(a=0;a<num_line_full-num_line_old;a++)
    b*=2;
 score1+=b-1;
 if(b>1)
    speed-=2;
 num_line_old=num_line_full;
 sprintf(str,"Your score:%d.",score1);
 outtextxy(20,20,str);
}

void save(void)/* 保存最高分值  */
{
 FILE * fp;
 int i;
 i=0;
 fp=fopen("bloscore.txt","rb+");
 i=(int)(fgetc(fp))-48;
 if(fp=NULL)
    i=0;
 fclose(fp);

 if(i<score1)
 {
    fp=fopen("bloscore.txt","wb+");
    fprintf(fp,"%d",score1);
    fclose(fp);
    printf("Your score: %d are the highest!",score1);
 }
 getch();

}

 


    编译运行需要一个文件:egavga.bgi,网络上可以下载到,我是存放在我的电脑的 c:/tc 目录下。

    这个程序还不是很完善,只是实现了基本功能,第一次的开始时,需要按一下方向键,最后的退出也有一点小问题,不过作为一个小游戏玩玩还是可以的了。

    有兴趣的朋友帮忙完善一下,加上了通知我一声哦。


后记:
 
    其实现在来发布贪吃蛇与俄罗斯方块这两个小游戏的源码,已经显不出有什么特别了,因为网络上已经有多个版本了。只是在2001年那时,这两个小游戏却是我的快乐与光荣。当时才学C语言,自己估摸着可以做点东西,就开始做了。都是我一个人编写与调试,在其他人玩乐的时候,是有一点孤单的。做出来后,看别人玩自己编写的游戏,很是自豪,不过却没有人来一起讨论编程中的得失,有些遗憾。现在虽然迟了,发布出来,也是了一个心愿吧。回头看以前编写的程序,格式不够规范,思路也很粗糙,远称不上完善,但那也是我成长过程中的一个脚印啊,与大家分享一下。

    这个游戏是我编写贪吃蛇之后的又一个尝试,本以为也只是几个方块的组合,类似于贪吃蛇,结果费了很大的功夫才编写成型,主要的困难在于边界的处理,需要非常仔细的考虑,否则bug一大堆呀。

  回头重看代码,确实很难看懂。就重新整理了一下,修改了一些变量、函数名称,添加了部分注释,增加一些代码可读性。

 

 

 

  • 8
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: IntelliJ IDEA是一款流行的Java集成开发环境,俄罗斯方块是一款经典的益智游戏。虽然IntelliJ IDEA可以用于开发任何类型的软件,但并不包含俄罗斯方块源码俄罗斯方块源码是由游戏开发者编写的,可能在其他开发工具中开发和编译。 如果你想获取俄罗斯方块源码,可以在互联网上搜索公开的源码库或者游戏开发者的个人网站。常见的俄罗斯方块源码使用Java语言编写,你可以下载并使用IntelliJ IDEA导入这些源码。 导入源码后,你可以在IntelliJ IDEA中运行和调试俄罗斯方块游戏。通过阅读源码,你可以了解到游戏的逻辑和实现细节,进一步学习Java编程技巧和游戏开发流程。 总之,IntelliJ IDEA是一个功能强大的开发工具,但它并不提供俄罗斯方块游戏源码。你需要在其他地方寻找和获取源码,并在IntelliJ IDEA中导入和编译它。 ### 回答2: IntelliJ IDEA是一款集成开发环境(IDE),它提供了强大的功能和工具,有助于开发人员更高效地编写代码。俄罗斯方块是一款经典的游戏,它的源码应该是由开发者编写的,用于实现游戏的功能和交互。 IntelliJ IDEA本身并不提供俄罗斯方块源码,因为它是一款通用的IDE,可以用于开发多种类型的应用程序,而不限于游戏。然而,通过使用IntelliJ IDEA,开发者可以方便地创建、管理和调试游戏源码。 实现俄罗斯方块需要涉及到图形界面、游戏逻辑、用户交互等方面。对于开发者来说,可以选择使用Java、C++、Python等编程语言来编写游戏源码。使用IntelliJ IDEA,可以方便地创建项目、编辑代码、调试程序,并通过IDE内置的工具进行版本控制和构建。 在编写俄罗斯方块源码时,开发者需要设计游戏的物理模型、图形绘制、碰撞检测等功能。这个过程需要一定的编程经验和算法思维。通过使用IntelliJ IDEA,可以轻松地实现这些功能,并且快速调试和测试代码。 由于篇幅所限,无法提供具体的源码示例。然而,通过在IntelliJ IDEA中搜索相关的游戏开发教程和样例项目,可以找到俄罗斯方块源码,并根据自己的需求进行修改和优化。 总结而言,IntelliJ IDEA是一款强大的IDE工具,可以方便开发者编写、管理和调试俄罗斯方块游戏源码。通过利用其提供的功能和工具,开发者可以更高效地实现游戏功能,并且可以根据需要进行定制和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值