俄罗斯方块
还记得俄罗斯方块吗?相信这是小时候我们每个人都喜欢玩的一个小游戏。顾名思义,俄罗斯方块自然是俄罗斯人发明的。这人叫阿列克谢·帕基特诺夫。他设置这个游戏的规则是:由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。
实现思路
那么问题就来了,如何用我们学过的C++去实现这个游戏呢?其实在写代码的时候,我们遵循的一个策略就是“拆分法”,从大的框架去一步步拆解成每个小的部分,然后这每个小的部分你都能用C++去实现它;要是拆分的小部分你还是实现不了,那就继续拆分,知道你能实现为止。比如这个俄罗斯方块的游戏,你的思路应该是这样:
1、画出游戏地图, 并留出下一图形和分数显示的位置
2、图形的建立和颜色
3、图形下落的实现以及上一图形的清除
4、是否能继续下落或变形的检测
5、某一行是否已满需清除以及清除功能与分数更新
实现代码如下
usingnamespacestd; classTetris{ private: intrank; //游戏难度等级intscore; // 得分intid; //图形IDintpoint[2]; //两基点inttop; //最高点高度public: Tetris(); voidWelocme(); //首界面voidDrawMap(); //游戏界面voidSetColor(int); //控制颜色voidDraw(int, int, int); //画图形voidRun(); //运行游戏voidReDraw(int, int, int); //清除图形boolJudge(int, int, int); voidTurn(int); //旋转voidUpdata(); // 更新界面voidPause(); //游戏暂停voidInput_score(); }; constintsharp[15][8] =//组成图形的各个点的各个坐标,先纵后横{ {0,0,1,0,2,0,3,0},{0,0,0,1,0,2,0,3}, {0,0,1,0,0,1,1,1}, {0,0,1,0,1,1,1,2},{0,1,1,1,2,0,2,1},{0,0,0,1,0,2,1,2},{0,0,0,1,1,0,2,0}, {1,0,1,1,1,2,0,2},{0,0,0,1,1,1,2,1},{0,0,0,1,0,2,1,0},{0,0,1,0,2,0,2,1}, {0,0,0,1,1,1,1,2},{0,1,1,0,1,1,2,0}, {0,1,0,2,1,0,1,1},{0,0,1,0,1,1,2,1} }; constinthigh[15] = { 4,1,2,2,3,2,3,2,3,2,3,2,3,2,3 }; intmap[28][16]; //条形// 方块//L形//T形//闪电1形//闪电2形Tetris::Tetris() //构造函数, 初始化各个值{ point[0] =0; point[1] =5; score=0; top=25; } voidTetris::Turn(intnum) //旋转函数{ switch (num) { casea1: id=a2; break; //条形互换casea2: id=a1; break; caseb: id=b; break; //方块无法旋转casec1: id=c2; break; //各种L形互换casec2: id=c3; break; casec3: id=c4; break; casec4: id=c1; break; cased1: id=d2; break; //各种T形互换cased2: id=d3; break; cased3: id=d4; break; cased4: id=d1; break; casee1: id=e2; break; //两种闪电形互换casee2: id=e1; break; casef1: id=f2; break; casef2: id=f1; break; } } voidSetPos(inti, intj) //控制光标位置, 列, 行{ COORDpos= { i,j }; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); } voidTetris::Pause() // 暂停函数{ SetPos(32, 10); cout<<"游戏暂停!"<<endl; SetPos(30, 11); cout<<"你的分数为 "<<score; chartemp; while (1) { while (1) { if (_kbhit()) { temp=_getch(); break; } } if (temp==32) break; } SetPos(32, 10); // 清除暂停时显示的信息cout<<" "; SetPos(30, 11); cout<<" "; } voidTetris::Updata() //更新函数{ inti, flag; intnx, ny; for (i=0; i<4; i++) { nx=point[0] +sharp[id][i*2]; ny=point[1] +sharp[id][i*2+1]; SetPos((ny+1) *2, nx+1); SetColor(0); cout<<"■"; map[nx][ny] =1; //界面各个点是否为空的更新 } if (point[0] <top) top=point[0]; //最高点的更新for (i=point[0]; i<point[0] +high[id]; i++) //消除行 { flag=1; for (intj=0; j<13; j++) //判定某一行是否满, 用flag来标记if (map[i][j] ==0) flag=0; if (flag==1) { for (intk=i; k>=top; k--) { for (intp=0; p<13; p++) { map[k][p] =map[k-1][p]; SetPos((p+1) *2, k+1); if (map[k][p] ==1) cout<<"■"; elsecout<<" "; } } score+=10; Input_score(); } } } voidTetris::Input_score() { SetColor(3); SetPos(30, 19); cout<<"得分: "<<score; } voidTetris::Welocme() //欢迎界面{ SetColor(1); charx; while (1) { system("cls"); cout<<"■■■■■■■■■■■■■■■■■■■■■"<<endl; cout<<" 俄罗斯方块 "<<endl; cout<<"■■■■■■■■■■■■■■■■■■■■■"<<endl; cout<<" 操作方式:"<<endl; cout<<" ↑ - 旋转"<<endl; cout<<" ↓ - 加速下移"<<endl; cout<<" ← - 左移"<<endl; cout<<" → - 右移"<<endl; cout<<" 空格 - 暂停"<<endl; cout<<"■■■■■■■■■■■■■■■■■■■■■"<<endl; cout<<"■ 按1—3选择难度■"<<endl; SetPos(20, 10); x=getchar(); if (x<='9'&&x>='0') { rank=x-'0'; break; } } } voidTetris::SetColor(intcolor_num) //设置颜色{ intn; switch (color_num) { case0: n=0x08; break; case1: n=0x0C; break; case2: n=0x0D; break; case3: n=0x0E; break; case4: n=0x0A; break; } SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n); } voidTetris::DrawMap() //画游戏时界面{ inti; SetColor(0); for (i=0; i<24; i++) //宽24格 { SetPos(i*2, 0); cout<<"■"; SetPos(i*2, 26); cout<<"■"; } for (i=0; i<26; i++) //高26格 { SetPos(0, i); cout<<"■"; SetPos(28, i); cout<<"■"; SetPos(46, i); cout<<"■"; } for (i=14; i<24; i++) { SetPos(i*2, 16); cout<<"■"; } SetColor(3); Input_score(); SetPos(30, 21); cout<<"难度等级: "<<rank; SetPos(32, 2); cout<<"下一图形"; } voidTetris::Draw(intx, inty, intnum) //画图形{ intnx, ny; for (inti=0; i<4; i++) { nx=x+sharp[num][2*i]; ny=y+sharp[num][2*i+1]; SetPos((ny+1) *2, nx+1); SetColor(i+1); cout<<"■"; } } voidTetris::ReDraw(intx, inty, intnum) //为更新图形的位置清除图形{ intnx, ny; for (inti=0; i<4; i++) { nx=x+sharp[num][2*i]; ny=y+sharp[num][2*i+1]; SetPos((ny+1) *2, nx+1); cout<<" "; } } boolTetris::Judge(intx, inty, intnum) //判定在x, y 所指位置是否可画编号为{ //num 的图形, 若不可画则反回trueintnx, ny; for (inti=0; i<4; i++) { nx=x+sharp[num][2*i]; ny=y+sharp[num][2*i+1]; if (!(nx<25&&nx>=0&&ny<13&&ny>=0&&!map[nx][ny])) returntrue; } returnfalse; } voidTetris::Run() //运行游戏{ intnext_id; srand((int)time(0)); id=rand() %15; next_id=rand() %15; Draw(point[0], point[1], id); Draw(5, 16, next_id); intcount; if (rank==1) count=150; elseif (rank==2) count=100; elseif (rank==3) count=50; elsecount=5; inti=0; //不同等级对应不同countwhile (1) { if (!(i<count)) //i 与 count 用于控制时间 { i=0; if (Judge(point[0] +1, point[1], id)) //在某一位置不能下落的话 { Updata(); id=next_id; ReDraw(5, 16, next_id); next_id=rand() %15; point[0] =0; point[1] =5; Draw(point[0], point[1], id); Draw(5, 16, next_id); if (Judge(point[0], point[1], id)) { system("cls"); SetPos(20, 10); cout<<"游戏结束!"<<endl; SetPos(20, 11); cout<<"你的分数为 "<<score<<endl; system("pause"); exit(1); } } else//继续下落 { ReDraw(point[0], point[1], id); point[0]++; Draw(point[0], point[1], id); } } if (_kbhit()) //键盘输入值时 { intkey, key2; key=_getch(); if (key==224) { key2=_getch(); if (key2==72) //按向上方向键时 { inttemp=id; Turn(id); if (Judge(point[0], point[1], id)) id=temp; ReDraw(point[0], point[1], temp); Draw(point[0], point[1], id); } if (key2==80) //按向下方向键时 { if (!Judge(point[0] +2, point[1], id)) { ReDraw(point[0], point[1], id); point[0] +=2; Draw(point[0], point[1], id); } } elseif (key2==75) //按向左方向键时 { if (!Judge(point[0], point[1] -1, id)) { ReDraw(point[0], point[1], id); point[1]--; Draw(point[0], point[1], id); } } elseif (key2==77) //按向右方向键时 { if (!Judge(point[0], point[1] +1, id)) { ReDraw(point[0], point[1], id); point[1]++; Draw(point[0], point[1], id); } } } elseif (key==32) // 按下空格暂停Pause(); } Sleep(1); //等待1毫秒i++; //控制下落间隔 } } intmain() { Tetrisgame; game.Welocme(); system("cls"); //清除欢迎界面game.DrawMap(); game.Run(); }
运行效果如下图所示
出现的问题
这个代码还是有一点问题的,如上图所示,需要后续不断改进。粉丝中有看了之后改进好了的,欢迎和我一起交流