记录一下我的成长历程,这是我学了C++之后,写的第一个程序,虽然比较简陋,但也不想改了,有兴趣的小伙伴可以参考一下。
#include<iostream>
#include<windows.h>
#include<conio.h>//使用getch()函数
#include<ctime>
#include <stdio.h>
using namespace std;
HANDLE handle;
COORD crd;//坐标
const short LMARGIN = 7;//方块掉落范围的左边界
const short TMARGIN = 5;//方块掉落范围的上边界
char type[19][17] =
{
//方块种类
"1100011000000000","0010011001000000",//Z型
"0110110000000000","0100011000100000",//S型
"0000111100000000","0100010001000100",//I型
"0000011001100000",//方型
"0100111000000000","0100110001000000","1110010000000000","1000110010000000",//T型
"0010111000000000","0110001000100000","1110100000000000","0100010001100000",//L型
"1000111000000000","0010001001100000","1110001000000000","0110010001000000"//J型
};
char rotate_hinder[19][17] =
{
//方块旋转受阻位置
"0010000001100000","1100000000100000",//Z型
"0000001011100000","0010100011000000",//S型
"1111000001110111","1011101100110011",//I型
"0000000000000000",//方型
"1010000011000000","1010001000100000","0000100010000000","0100001001100000",//T型
"0100000011100000","1000110000000000","0000010011100000","1010101000000000",//L型
"0110000011100000","1010101000100000","0000110011000000","1000101000100000"//J型
};
short Alter(short n)//旋转函数
{
switch (n)
{
case 1:case 3:case 5:return n - 1; break;
case 6:return 6; break;
case 10:case 14:case 18:return n - 3; break;
default:return n + 1; break;
}
}
void SetPos(short x, short y)//坐标函数
{
crd.X = x; crd.Y = y;
SetConsoleCursorPosition(handle, crd);
}
void SetColor(short front, short back)//颜色
{
SetConsoleTextAttribute(handle, front + back * 0x10);
}
void PrintGameOver()
{
SetPos(12, 9);
SetColor(5, 6);
cout << "Game Over!";
SetColor(7, 0);
}
class Score
{
private:
short ln;//得分
public:
void Reset() { ln = 0; }
void Print()
{
SetPos(4, 1);
SetColor(2, 7);
cout << "Lines: " << ln << " ";
SetColor(7, 0);
}
Score() { Reset(); }
void Update(short n) { ln += n; }
};
class Shape//方块类
{
private:
short present;//当前形状
short color;
short x;//左上角横坐标
short y;//左上角纵坐标
public:
Shape(short, short, short);//颜色、坐标
void Draw(bool, bool);//第一个参数为真执行绘制操作,为假执行擦除;第二个参数为真按方块颜色画,为假画成白色
friend class Board;
bool Rotate(Board& brd);//判断方块能否旋转,如果能则旋转并返回真,如果不能旋转则返回假
short Collision(Board& brd);//左侧,右侧,下方受阻时,返回值分别“位或”1,2,4
bool Move(short, Board& brd);//左移动第一个参数为1,右移动第一个参数为2
bool Fall(Board& brd);//能下落返回true,不能下落返回false
void DrawElseWhere(short _x, short _y);//在操作区外面显示一个方块的初始形状
};
class Board//游戏框类
{
private:
bool wall[22][14];
short bottom_line;//保存当前可以消除的最下面一行的行号
public:
void Clear()//重置数组元素的值
{
for (short i = 0; i < 22; i++)
for (short j = 0; j < 14; j++)
if (j > 1 && j < 12 && i < 20)
wall[i][j] = 0;
else
wall[i][j] = 1;
}
Board() { Clear(); }
void DrawBoard()
{
short i;
SetColor(0xe, 0);//十进制的14
for (i = 0; i < 21; i++)//绘制左边界
{
SetPos(LMARGIN - 2, TMARGIN + i - 1);
cout << "■";
}
for (i = 0; i < 21; i++)
{
SetPos(LMARGIN + 20, TMARGIN + i - 1);
cout << "■";
}
for (i = 0; i < 10; i++)
{
SetPos(LMARGIN + i * 2, TMARGIN + 19);
cout << "■";
}
SetColor(7, 0);
}
short SetBlocValue(Shape& shp)//对wall数组的值更新
{
for (short i = 0; i < 16; i++)
if (type[shp.present][i] == '1')
{
if (shp.y == 0)//检查游戏有没有结束
return -1;
wall[shp.y + i / 4][shp.x + i % 4] = true;
}
return 0;
}
short Drop(Shape& shp)//返回可以消除的行数
{
short i, n;//i用于遍历方块所在的16个字符,n用来保存检测过的被方块占用的格子数
short j;//用于遍历一整行检查是否有wall数组的元素为false
short k;//用于从上往下逐行往下覆盖
short y, _y = -1;//y用于保存当前格子的行号,_y用于保存前一个格子的行号,初始化一个不合理值,确保第一轮对比不相等
short lines = 0;//保存了消除多少排
short top;//用于检测有没有遍历到堆积块的顶部
short l;//在覆盖的操作当中从左到右遍历
for (i = 0, n = 0; n < 4 && i < 16; i++)
{
if (type[shp.present][i] == '1')
{
y = shp.y + i / 4;
n++;
if (y == _y)//两个格子处于同一横排不必进行两次消除判断
continue;
_y = y;
for (j = 2; j < 12; j++)
if (!wall[y][j])
break;
if (j == 12)//一整排已经填满,应消除
{
lines++;
for (k = y; k > 0; k--)
{
top = 0;
for (l = 2; l < 12; l++)
{
wall[k][l] = wall[k - 1][l];
top += wall[k - 1][l];
}
if (top == 0)
break;//终止从上到下的遍历
}
}
}
}
bottom_line = _y;
return lines;
}
void DrowPile()//重绘堆积块,有bottom_line指定需要重绘的最下面一行
{
for (short i = 0; i <= bottom_line; i++)//行遍历
{
for (short j = 2; j < 12; j++)//列遍历
{
SetPos(LMARGIN - 4 + j * 2, TMARGIN - 1 + i);
if (wall[i][j])
{
SetColor(7, 7);//白色用于绘出
cout << "□";
}
else
{
SetColor(0, 0);//黑色用于擦除
cout << " ";
}
}
}
}
friend class Shape;
};
Shape::Shape(short _color, short _x = 5, short _y = 0) :color(_color), x(_x), y(_y)
{
switch (_color)
{
case 1:present = 0; break;
case 2:present = 2; break;
case 3:present = 4; break;
case 4:present = 6; break;
case 5:present = 7; break;
case 6:present = 11; break;
default:color = 8; present = 15; break;
}
}
void Shape::Draw(bool flag = true, bool active = true)
{
if (!flag)//擦除
SetColor(0, 0);
else
if (active)
SetColor(color, color);//按方块颜色画
else
SetColor(7, 7);//落地方块画成白色
for (short i = 0; i < 16; i++)
if (type[present][i] == '1')
{
SetPos(LMARGIN - 4 + (x + i % 4) * 2, TMARGIN + y + i / 4 - 1);
cout << "□";
}
SetColor(7, 0);
}
bool Shape::Rotate(Board& brd)
{
for (short i = 0; i < 16; i++)
{
if (brd.wall[y + i / 4][x + i % 4] && rotate_hinder[present][i] == '1')//如果格局中的一个位置被占用,并且这个位置能阻碍旋转
return false;
}
Draw(false);
present = Alter(present);
Draw();
return true;
}
short Shape::Collision(Board& brd)
{
short result = 0;
for (short i = 0; i < 16; i++)
{
if (type[present][i] == '1')//该格子被当前方块占用
{
if (brd.wall[y + i / 4][x + i % 4 - 1])
result |= 1;//左受阻
if (brd.wall[y + i / 4][x + i % 4 + 1])
result |= 2;//右受阻
if (brd.wall[y + i / 4 + 1][x + i % 4])
result |= 4;//下受阻
}
}
return result;
}
bool Shape::Move(short direction, Board& brd)
{
if (direction == 1 && !(Collision(brd) & 1))//表达式Collision(brd)&1为0,说明左侧没有受阻,取反之后条件为true
{
Draw(false, true);
x--;
Draw();
return true;
}
if (direction == 2 && !(Collision(brd) & 2))//表达式Collision(brd)&2为0,说明右侧没有受阻,取反之后条件为true
{
Draw(false, true);
x++;
Draw();
return true;
}
return false;
}
bool Shape::Fall(Board& brd)
{
if (Collision(brd) & 4)//已经着地
{
Draw(true, false);
return false;
}
Draw(false, true);
y++;
Draw();
return true;
}
void Shape::DrawElseWhere(short _x, short _y)
{
short i;
SetPos(_x, _y);
SetColor(7, 0);
cout << "Next: ";
_x += 6;
SetColor(0, 0);
SetPos(_x, _y);
for (i = 0; i < 12; i++)//擦除上一个方块,方块的初始形状不会占据最后一行,只需要遍历12格就行
{
SetPos(_x + i % 4 * 2, _y + i / 4);
cout << " ";
}
SetColor(color, color);
_y -= (present == 6 || present == 4);//将方块和棍子形状向上提升一格
for (i = 0; i < 12; i++)//绘制下一个方块
{
if (type[present][i] == '1')
{
SetPos(_x + i % 4 * 2, _y + i / 4);
cout << "□";
}
}
}
short Menu()//菜单函数,选中开始游戏返回1,离开返回2
{
short choice = 1;
char c;//记录按键信息
system("cls");
SetPos(9, 12);
cout << "┌────────────────┐";
SetPos(9, 13);
cout << "│ 俄 罗 斯 方 块 │";
SetPos(9, 14);
cout << "└────────────────┘";
SetPos(7, 21);
cout << "按下方向键控制方块";
SetPos(7, 23);
cout << "按空格键暂停/继续";
while (1)
{
SetPos(15, 16);
if (choice == 1)
SetColor(2, 7);
else
SetColor(2, 0);
cout << "开始游戏";
SetPos(15, 18);
if (choice == 2)
SetColor(2, 7);
else
SetColor(2, 0);
cout << "离 开";
c = _getch();
if (c == 13)
break;
else if (c == 0)//没有这条语句的话,按下方向键,循环体会执行两遍
c = _getch();//方向键比较特殊,第一次获取c的值为0,第二次才是72,或者80
if (c == 72 || c == 80)
choice = choice == 1 ? 2 : 1;
}
SetColor(7, 0);
return choice;
}
int main()
{
system("mode con cols=35 lines=27");//设置控制台尺寸
handle = GetStdHandle(STD_OUTPUT_HANDLE);
Board board;
short tmp;//用来保存一个方块消去的行数
Shape* shp, * shp_next;
Score score;
short times;//用于保存执行Sleep函数的次数
srand(time(0));
char c;//用于记录按键信息
while (Menu() == 1)//一次游戏的过程
{
system("cls");
board.Clear();
board.DrawBoard();
score.Reset();//得分归零
score.Print();//显示得分
shp_next = new Shape(rand() % 7 + 1);
while (1)//一个方块落地的过程
{
shp = shp_next;//将下一个方块赋给当前方块
shp_next = new Shape(rand() % 7 + 1);//新产生下一个方块
shp_next->DrawElseWhere(17, 1);//显示下一个方块
times = 0;
while (1)//捕捉一次按键的过程,循环10次下落一格
{
shp->Draw();
if (GetAsyncKeyState(VK_LEFT) == -32767)//VK_LEFT是左方向键的虚拟键码
shp->Move(1, board);
if (GetAsyncKeyState(VK_RIGHT) == -32767)//VK_RIGHT是右方向键的虚拟键码
shp->Move(2, board);
if (GetAsyncKeyState(VK_UP) == -32767)//VK_UP是上方向键的虚拟键码
shp->Rotate(board);
if (GetAsyncKeyState(VK_DOWN) == -32767)//VK_DOWN是下方向键的虚拟键码
shp->Fall(board);
if (GetAsyncKeyState(VK_SPACE) == -32767)//空格键暂停
{
while (!(GetAsyncKeyState(VK_SPACE) == -32767))//没有按下空格键延时25毫秒继续循环,再次按下空格键继续
Sleep(25);
}
Sleep(25);//延时
times++;
if (times == 10)
{
times = 0;
if (!shp->Fall(board))
break;
}
}
if (board.SetBlocValue(*shp) == -1)
{
PrintGameOver();
fflush(stdin);//清空输入流
while ((c = getchar()) != '\n' && c != EOF);
delete shp_next;
break;
}
if (tmp = board.Drop(*shp))
{
board.DrowPile();
score.Update(tmp);//累加得分
score.Print();//显示得分
}
//.........
delete shp;
}
}
return 0;
}
传送门: