diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1dc7ec5 --- /dev/null +++ b/main.cpp @@ -0,0 +1,469 @@ +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +//建立图形的坐标 +int Map[24][8] = { +{0,0,1,0,2,0,3,0},{0,0,0,1,0,2,0,3},{0,0,1,0,2,0,3,0},{0,0,0,1,0,2,0,3},//l型 +{0,0,1,0,0,1,1,1},{0,0,1,0,0,1,1,1},{0,0,1,0,0,1,1,1},{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},//L型 +{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},//反L型 +{0,0,0,1,1,1,1,2},{0,1,1,0,1,1,2,0},{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},{0,1,0,2,1,0,1,1},{0,0,1,0,1,1,2,1} //反⚡型 +}; +int height[24] = { 4,1,4,1,2,2,2,2,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3 };//每个图形的高度 +void HideCursor()//隐藏光标 +{ + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + CONSOLE_CURSOR_INFO CursorInfo; + GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息 + CursorInfo.bVisible = false; //隐藏控制台光标 + SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态 +} +void SetPos(int i, int j)//设定光标位置 +{ + COORD pos = { i,j }; + SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); +} +class Box //游戏的类 +{ +private: + int map[30][30];//记录哪些位置有方块 + int point = 0;//记录分数 + int shape;//记录是哪个图形 + int speed = 0;//速度 + int top;//当前图形的最高位置 + int level;//难度 + struct Base//基准点坐标 + { + int x, y; + }base; +public: + Box()//初始化 + { + shape = 0, point = 0; top = 9999; level = 0; + base.x = 0; base.y = 6; + memset(map, 0, sizeof(map)); + } + void buildmap();//画地图 + void menu();//开始菜单 + void run();//游戏运行 + void rotate();//旋转图形 + void draw(int x, int y, int Shape);//绘制图形 + void erase(int x, int y, int Shape);//删除图形 + int judgeshape();//产生一个形状 + bool judge(int x, int y, int shape);//判断是否可以画方格 + void Move(char c);//判断键盘输入并处理 + void update();//更新地图 + void color(int shape);//给方块设定颜色 +}; +void Box::menu() //开始菜单 +{ + cout << endl << endl << endl; + cout << "***********************************" << endl; + cout << "****** ******" << endl; + cout << "****** #俄罗斯方块# ******" << endl; + cout << "****** ******" << endl; + cout << "****** 致敬童年,回味无穷 ******" << endl; + cout << "****** ******" << endl; + cout << "****** 选择难度(1~9): ******" << endl; + cout << "****** ******" << endl; + cout << "***********************************" << endl << endl; + cout << "控制:\nA/a:左移 W/w:变换\nD/d:右移 P/p:暂停\nS/s:加速 Q/q:退出\n"; + SetPos(25, 9); + while (1) + { + if (_kbhit()) + { + int n; cin >> n; + if (1 <= n && n <= 9) + { + level = n; + system("cls"); + break; + } + } + } +} +void Box::buildmap() //初始地图 +{ + int i; + for (i = 0; i < 16; i++)//游戏主界面大方格 + { + SetPos(i * 2, 0);//控制光标位置 + cout << "■";//每个图形占两列 + } + for (i = 1; i <= 28; i++) + { + SetPos(0, i); + cout << "■"; + SetPos(30, i); + cout << "■"; + } + for (i = 0; i < 16; i++) + { + SetPos(i * 2, 28); + cout << "■"; + } + + for (i = 17; i <= 26; i++) + { + SetPos(i * 2, 0); + cout << "■"; + } + for (i = 1; i <= 8; i++) + { + SetPos(17 * 2, i); + cout << "■"; + SetPos(26 * 2, i); + cout << "■"; + } + for (i = 17; i <= 26; i++) + { + SetPos(i * 2, 9); + cout << "■"; + } + SetPos(38, 14); + cout << "俄罗斯方块"; + SetPos(38, 16); + cout << "难度:" << level; + SetPos(38, 18); + cout << "分数:" << point; +} +void Box::rotate() //旋转图形,改变输出坐标 +{ + switch (shape) + { + case 0:shape = 1; break; + case 1:shape = 0; break; + case 4:break; + case 8:shape = 9; break; + case 9:shape = 10; break; + case 10:shape = 11; break; + case 11:shape = 8; break; + case 12:shape = 13; break; + case 13:shape = 14; break; + case 14:shape = 15; break; + case 15:shape = 12; break; + case 16:shape = 17; break; + case 17:shape = 16; break; + case 20:shape = 21; break; + case 21:shape = 20; break; + } +} +void Box::draw(int x, int y, int Shape) //绘制图形 +{ + int xx, yy; + for (int i = 0; i < 4; i++) + { + //由于方格占两行两列,所以需要*2 + xx = x + Map[Shape][i * 2]; yy = y + Map[Shape][i * 2 + 1]; + SetPos((yy + 1) * 2, xx + 1); + cout << "■"; + } +} +void Box::erase(int x, int y, int Shape) //删除原图形 +{ + int xx, yy; + for (int i = 0; i < 4; i++) + { + xx = x + Map[Shape][i * 2]; yy = y + Map[Shape][i * 2 + 1]; + SetPos((yy + 1) * 2, xx + 1); + cout << " "; //用两个空格填充原图形 + } +} +int Box::judgeshape() //产生一个随机的图形 +{ + int x = rand() % 24; + if (x < 4) return 0; + else if (x >= 4 && x <= 7) return 4; + else if (x >= 8 && x <= 11) return 8; + else if (x >= 12 && x <= 15) return 12; + else if (x >= 16 && x <= 19) return 16; + else return 20; +} +bool Box::judge(int x, int y, int shape) //判断当前是否可以绘制方块 +{ + int i; + int nx, ny; + for (i = 0; i < 4; i++) + { + nx = x + Map[shape][i * 2]; + ny = y + Map[shape][i * 2 + 1]; + if (nx < 0 || nx >= 27 || ny < 0 || ny >= 14 || map[nx][ny] == 1) + return 0; + } + return 1; +} +void Box::Move(char c) //读取键盘输入处理 +{ + if (c == 'A' || c == 'a') + { + if (judge(base.x, base.y - 1, shape)) + { + erase(base.x, base.y, shape); + base.y -= 1; + draw(base.x, base.y, shape); + } + } + else if (c == 'D' || c == 'd') + { + if (judge(base.x, base.y + 1, shape)) + { + erase(base.x, base.y, shape); + base.y += 1; + draw(base.x, base.y, shape); + } + } + else if (c == 'S' || c == 's') + { + if (judge(base.x + 3, base.y, shape))//下三格没有方格才可以加速 + { + erase(base.x, base.y, shape); + base.x += 2; //让坐标下降一个方格 + draw(base.x, base.y, shape); + } + } + else if (c == 'W' || c == 'w') + { + int t = shape; + rotate(); + if (judge(base.x, base.y, shape))//判断是否可以旋转 + { + erase(base.x, base.y, t); + draw(base.x, base.y, shape); + } + else + { + shape = t; + } + } + else if (c == 'Q' || c == 'q') + { + system("cls"); + color(-1); + buildmap(); + SetPos(5, 13); + cout << " 游戏结束 "; + SetPos(5, 14); + cout << " 最终分数为:" << point; + SetPos(0, 29); + system("pause"); + exit(0); + } + else if (c == 'P' || c == 'p') + { + color(-1); + SetPos(5, 13); + cout << " 游戏已暂停 "; + SetPos(5, 14); + cout << " 按P/p键继续 "; + while (1) + { + if (_kbhit()) + { + char cc = _getch(); + if (cc == 'P' || cc == 'p')//暂停后再次按P继续游戏 + { + SetPos(5, 13); + cout << " ";//将上面两行字删除 + SetPos(5, 14); + cout << " "; + break; + } + } + } + } +} +void Box::update() //更新地图 +{ + int xx, yy; + for (int i = 0; i < 4; i++)//将图形所在的位置标记 + { + xx = base.x + Map[shape][i * 2]; + yy = base.y + Map[shape][i * 2 + 1]; + map[xx][yy] = 1; + } + if (base.x < top)//记录当前的最高点 + { + top = base.x; + } + int num = 0;//记录需要清除的行数,即分数 + for (int i = base.x; i < base.x + height[shape]; i++)//从现在图形的基点向下 + { + int flag = 1;//判断这一行是否可以消除 + for (int j = 0; j < 14; j++) + { + if (map[i][j] == 0) + { + flag = 0; break; + } + } + if (flag)//可以消除 + { + for (int j = i; j >= top; j--)//从可以消除的一行开始,上面所有方格下移一行 + { + if (j == 0)//特判如果这一行是第0行 + { + for (int k = 0; k < 14; k++) + { + map[j][k] = 0; + SetPos((k + 1) * 2, j + 1); + cout << " "; + } + } + else + { + for (int k = 0; k < 14; k++) + { + map[j][k] = map[j - 1][k]; + SetPos((k + 1) * 2, j + 1); + color(-1);//将颜色设定为白色 + if (map[j][k] == 1) + cout << "■"; + else + cout << " "; + } + } + } + top++;//top下移,防止重复更新 + num++; + point += num * 100; + } + else//不能删除这一行 + { + for (int j = base.x + height[shape] - 1; j >= base.x; j--) + { + for (int k = 0; k < 14; k++) + { + SetPos((k + 1) * 2, j + 1); + color(-1);//将颜色设置为白色 + if (map[j][k] == 1) + cout << "■"; + else + cout << " "; + } + } + } + } + SetPos(38, 18);//更新分数 + cout << "分数:" << point; +} +void Box::color(int x) //设置颜色 +{ + if (x >= 0 && x < 4)//设为红色 + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED); + } + else if (x >= 4 && x <= 7)//设为绿色 + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); + } + else if (x >= 8 && x <= 11)//设为蓝色 + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE); + } + else if (x >= 12 && x <= 15)//设为橘色 + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN); + } + else if (x >= 16 && x <= 19)//设为天蓝色 + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_BLUE | FOREGROUND_GREEN); + } + else if (x >= 20 && x <= 23)//设为紫色 + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_BLUE); + } + else if (x == -1)//设为白色 + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); + } +} +void Box::run() //运行游戏 +{ + buildmap(); //绘制地图 + SetPos(7, 11); + cout << "按任意键开始!"; + while (1)//按任意键开始游戏 + { + if (_kbhit()) + { + system("cls"); + color(-1);//白色 + buildmap(); + break; + } + } + srand(unsigned(time(0)));//利用系统时间随机数产生随机图形 + shape = judgeshape();//现在的图形 + int nextshape = judgeshape();//下一个图形 + color(shape);//更改输出的图形颜色 + draw(base.x, base.y, shape);//绘制图形 + color(nextshape); + draw(3, 20, nextshape); + speed = 100 - level * 10;//设置图形下落速度,根据所选难度不同速度不同 + color(shape); + int cnt = 0; //记录当前经过多少时间 + while (1)//每次循环时间为1毫秒 + { + if (cnt >= speed)//超过50毫秒后自动向下移动 + { + cnt = 0;//计数器归零 + if (judge(base.x + 1, base.y, shape))//下一格没有方块,图形下移一格 + { + erase(base.x, base.y, shape); + color(shape); + draw(base.x + 1, base.y, shape); + base.x += 1; + } + else //下一格有方块 + { + update();//更新图形 + shape = nextshape;//更新当前图形为下一个图形 + nextshape = judgeshape();//生成新的下一个图形 + erase(3, 20, shape); + color(nextshape); + draw(3, 20, nextshape); + base.x = 0; base.y = 5;//更新基点 + color(shape); + draw(base.x, base.y, shape); + if (!judge(base.x, base.y, shape))//如果不能绘制图形,说明到达顶点,游戏结束 + { + color(-1); + SetPos(5, 13); + cout << " 游戏结束 "; + SetPos(5, 14); + cout << " 最终分数为:" << point; + SetPos(0, 29); + system("pause"); + exit(0); + } + } + } + if (_kbhit())//如果有键盘输入 + { + char c = _getch(); + Move(c);//判断处理键盘输入 + while (_kbhit())//读掉剩下的键盘信息 + _getch(); + } + Sleep(1);//等待1毫秒 + cnt++;//计数器+1 + } +} +int main() +{ + Box Tetrisl;//创建俄罗斯方块类 + system("mode con cols=120 lines=42");//调整窗口大小 + Tetrisl.menu();//显示游戏开始菜单 + HideCursor();//游戏开始后隐藏光标 + Tetrisl.run();//游戏运行 + system("pause"); + return 0; +}