You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<windows.h>
#include<conio.h>
#include<deque>
#include<ctime>
#include<stdexcept>
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;
}