|
|
#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;
|
|
|
}
|