俄罗斯方块代码解析
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<windows.h> 4 #include<time.h> 5 #include<conio.h> 6 #define MOD 28 //28种模式 7 #define SIZE_N 19 //设置高度和宽度 8 #define SIZE_M 12 9 int cur_x,cur_y; 10 int score,mark,next,map[SIZE_N][SIZE_M],Gamespeed=3000; //设置下落速度 11 int shape[28][6]=//一共7种方法,加上旋转4种形状,28种,另外坐标本是8位,因总有小方块坐标在原点,故省去 12 { 13 14 {0,-1,0,-2,1,0}, {0,1,1,0,2,0}, {-1,0,0,1,0,2}, {0,-1,-1,0,-2,0}, 15 16 {0,-1,0,1,-1,0}, {0,1,1,0,-1,0}, {1,0,0,-1,0,1}, {1,0,-1,0,0,-1}, 17 18 {-1,1,0,1,1,0}, {0,-1,1,0,1,1}, {-1,0,0,-1,1,-1}, {-1,-1,-1,0,0,1}, 19 20 {-1,0,0,1,1,1}, {0,1,1,-1,1,0}, {-1,0,0,1,1,1}, {0,1,1,-1,1,0}, 21 22 {-1,0,0,-1,0,-2}, {-1,0,-2,0,0,1}, {0,1,0,2,1,0}, {0,-1,1,0,2,0}, 23 24 {0,1,1,0,1,1}, {0,-1,1,0,1,-1}, {-1,0,0,-1,-1,-1}, {-1,0,-1,1,0,1}, 25 26 {0,1,0,2,0,3}, {1,0,2,0,3,0}, {0,-1,0,-2,0,-3}, {-1,0,-2,0,-3,0} 27 28 }; 29 30 void gotoxy(int x,int y)//gotoxy本是TC中system.h库文件里的一个函数,但在VC不可直接用,故需如此定义,直接跳转到某个坐标 31 { 32 COORD c; 33 c.X=x-1; c.Y=y-1; 34 SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), c); 35 } 36 37 void Gameover()//对游戏结束进行判断 38 { 39 int i,j,flag=0; 40 for(j=1;j<SIZE_M-1;j++) 41 { 42 if(map[1][j]!=0) 43 { 44 flag=1; 45 break; //跳出整个for循环 46 } 47 } 48 if(flag==1) 49 { 50 for(i=1;i<SIZE_N-1;i++) 51 { 52 gotoxy(2,i+1); 53 for(j=1;j<SIZE_M-1;j++) 54 { 55 printf("□"); 56 } 57 puts(""); 58 } 59 gotoxy(7,9); 60 printf("GAME OVER!"); 61 gotoxy(1,SIZE_N+1); 62 exit(0); 63 } 64 65 } 66 67 void ShowMap(int id)//设置整个方块的活动区域 68 { 69 int i,j; 70 gotoxy(1,1); 71 if(id!=-1) 72 { 73 for(i=0;i<SIZE_N;i++) 74 { 75 for(j=0;j<SIZE_M;j++) 76 { 77 if(i==0&&j==0 || i==0&&j==SIZE_M-1 || j==0&&i==SIZE_N-1 || j==SIZE_M-1&&i==SIZE_N-1) 78 printf(" "); 79 else 80 if(i==0 || i==SIZE_N-1) 81 printf("--"); 82 else 83 if(j==0 || j==SIZE_M-1) 84 printf("|"); 85 else 86 if(map[i][j]==2) 87 printf("■"); 88 else // cur_x=0; cur_y=5; 89 if(i==cur_x+shape[id][0] && j==cur_y+shape[id][1] || 90 i==cur_x+shape[id][2] && j==cur_y+shape[id][3] || 91 i==cur_x+shape[id][4] && j==cur_y+shape[id][5] || 92 i==cur_x && j==cur_y) 93 printf("■"); 94 else 95 if(map[i][j]==0) 96 printf(" "); 97 } 98 if(i==1)printf(" next:"); 99 if(i==11)printf(" score : %d",score); 100 if(i==14)printf(" speed : %d",score/100+1); 101 puts(""); 102 } 103 } 104 else { 105 mark=1; 106 for(i=0;i<SIZE_N;i++) 107 { 108 for(j=0;j<SIZE_M;j++) 109 { 110 if(i==0&&j==0 || i==0&&j==SIZE_M-1 || j==0&&i==SIZE_N-1 || j==SIZE_M-1&&i==SIZE_N-1) 111 printf(" "); 112 else 113 if(i==0 || i==SIZE_N-1) 114 printf("--"); 115 else 116 if(j==0 || j==SIZE_M-1) 117 printf("|"); 118 else 119 if(map[i][j]==2) 120 printf("■"); 121 else 122 if(map[i][j]==0) 123 printf(" "); 124 } 125 if(i==1) 126 printf(" next:"); 127 if(i==11) 128 printf(" score : %d",score); 129 if(i==14) 130 printf(" speed : %d",score/100+1); 131 puts(""); 132 } 133 } 134 135 /*对于 next 方块的处理,先擦除再画图*/ 136 gotoxy(30,6); 137 printf(" "); 138 for(i=0;i<6;i=i+2) 139 { 140 gotoxy(30+2*shape[id][i+1],6+shape[id][i]); 141 printf(" "); 142 } 143 gotoxy(30,6); 144 printf("■"); 145 for(i=0;i<6;i=i+2) 146 { 147 gotoxy(30+2*shape[next][i+1],6+shape[next][i]); 148 printf("■"); 149 } 150 Sleep(Gamespeed); //Sleep()定时停顿时间 151 } 152 153 154 155 void init(int id)//初始化函数,cur_x,cur_y是全局变量,标记了移动方块的位置 156 { 157 int i,j; 158 memset(map,0,sizeof(map));//将map元素全部初始化为0 159 for( i=0;i<SIZE_N;i++) 160 { 161 for( j=0;j<SIZE_M;j++) 162 if(i==SIZE_N-1 || j==0 || j==SIZE_M-1) //靠近最顶端设置为-1 163 map[i][j]=-1; 164 } 165 cur_x=0; cur_y=5; //初始化 166 ShowMap(id); 167 } 168 169 170 171 int judge_in(int x,int y,int id){/*/判断是否出界,或者说是否合法*/ 172 173 int i; 174 if(map[x][y]!=0) 175 return 0; 176 for( i=0;i<6;i=i+2) 177 { 178 if(map[ x+shape[id][i] ][ y+shape[id][i+1] ]!=0) 179 return 0; 180 } 181 return 1; 182 } 183 184 185 186 void fun_score() 187 { 188 //得分,擦除行的闪烁,还有图形的向下平移 189 int i,j,flag=0; 190 int k,ii,jj; 191 for( i=1;i<SIZE_N-1;i++) 192 { 193 flag=0; 194 for(j=1;j<SIZE_M-1;j++) 195 { 196 if(map[i][j]!=2) 197 { 198 flag=1; 199 break; 200 } 201 } 202 if(flag==0) 203 { 204 k=3; 205 while(k--) 206 { 207 gotoxy(2,i+1); 208 for( ii=1;ii<SIZE_M-1;ii++) 209 { 210 if(map[i][ii]==2) 211 { 212 if(k%2==1) 213 printf(" "); 214 else printf("■"); 215 } 216 } 217 Sleep(100); 218 } 219 for( ii=i;ii>1;ii--) 220 { 221 222 for(jj=1;jj<SIZE_M-1;jj++) 223 map[ii][jj]=map[ii-1][jj]; 224 } 225 ShowMap(-1); 226 score+=10; 227 if(score%100==0 && score!=0) 228 Gamespeed-=50; 229 } 230 231 } 232 233 } 234 235 236 237 int main(){ 238 239 int i,id,set=1; 240 srand(time(NULL)); //srand((unsigned)time(NULL))设置随机种子 241 id=rand()%MOD; //分配随机数id值 242 next=rand()%MOD; //next值 243 init(id); //id 244 while(1) 245 { 246 Here: mark=0; //进行goto语句的使用,分数设置为0 247 if(set==0) 248 { 249 id=next; 250 next=rand()%MOD; 251 next=(next+MOD)%MOD; 252 cur_x=0;cur_y=5; 253 set=1; 254 } 255 while(!kbhit())//kbhit默认为0 256 { 257 Gameover(); //调用Gameover()函数 258 if(judge_in(cur_x+1,cur_y,id)==1) 259 cur_x++; 260 else 261 { 262 map[cur_x][cur_y]=2; 263 for(i=0;i<6;i=i+2) 264 map[ cur_x+shape[id][i] ][ cur_y+shape[id][i+1] ]=2; 265 fun_score(); 266 set=0; 267 } 268 if(mark!=1) 269 ShowMap(id); 270 goto Here; 271 272 }/*/end of while(!kbhit())*/ 273 char key; 274 key=getch(); 275 if(key==72){ 276 int tmp=id; 277 id++; 278 if( id%4==0 && id!=0 ) 279 id=id-4; 280 if(judge_in(cur_x,cur_y,id)!=1) 281 id=tmp; 282 } 283 else if(key==80 && judge_in(cur_x+1,cur_y,id)==1) 284 cur_x++; 285 else if(key==75 && judge_in(cur_x,cur_y-1,id)==1) 286 cur_y--; 287 else if(key==77 && judge_in(cur_x,cur_y+1,id)==1) 288 cur_y++; 289 else if(key==27) 290 { 291 gotoxy(1,SIZE_N+1); 292 exit(0); 293 } 294 } 295 return 0; 296 }
(0,2) |
||||
(0,1) |
||||
(-2,0) |
(-1,0) |
(0,0) |
(1,0) |
(2,0) |
(0,-1) |
||||
(0,-2) |
||||
- 每个坐标代表一个方块样式,一共有28组坐标,代表28个方块式样。
2.由于在控制台下,光标的初始位置一般是在左上角,所以这里以左上角为原点(0,0),向下为X轴正方向,向右为Y轴正方向。
3.每组坐标有6个数字,实际上有8个数字,只是因为第一位和第二位恒为0,故省略。这样,从第一位开始,每相邻的两个数字为一组,一共得到4组坐标,即为俄罗斯方块中的小方块坐标(常规俄罗斯方块一共有4个小方块)。
4.你可以动手画一画。例如:{-1,0,0,1,0,2},细分为:(x1=0,y1=0),(x2=-1,y2=0),(x3=0,y3=1),(x4=0,y4=2).如图: