效果
实现细节
所有的数据都存放在地图数组中,种类有三种:
class Tetris
{
private:
// 背景数组 0:无方块 1:在下落的方块 2:底部固定的方块
char background[20][10];
}
地图坐标系:
7种方块:
class Tetris
{
private:
// 方块数组
char sqare[2][4];
// 标记产生随机方块的种类
int sqareId = 0;
// 记录判断能否旋转的点的位置x
int line = 0;
// 记录判断能否旋转的点的位置y
int list = 0;
}
// 创建一个随机的方块
int Tetris::createRandSqare()
{
sqareId = rand() % 7; // 总共七种方块类型
switch (sqareId)
{
case 0:
// ■ ■
// ■ ■
sqare[0][0] = 1, sqare[0][1] = 1, sqare[0][2] = 0, sqare[0][3] = 0;
sqare[1][0] = 0, sqare[1][1] = 1, sqare[1][2] = 1, sqare[1][3] = 0;
line = 0;
list = 3;
break;
case 1:
// ■ ■
// ■ ■
sqare[0][0] = 0, sqare[0][1] = 1, sqare[0][2] = 1, sqare[0][3] = 0;
sqare[1][0] = 1, sqare[1][1] = 1, sqare[1][2] = 0, sqare[1][3] = 0;
line = 0;
list = 3;
break;
case 2:
// ■
// ■ ■ ■
sqare[0][0] = 0, sqare[0][1] = 0, sqare[0][2] = 1, sqare[0][3] = 0;
sqare[1][0] = 1, sqare[1][1] = 1, sqare[1][2] = 1, sqare[1][3] = 0;
line = 0;
list = 3;
break;
case 3:
// ■
// ■ ■ ■
sqare[0][0] = 1, sqare[0][1] = 0, sqare[0][2] = 0, sqare[0][3] = 0;
sqare[1][0] = 1, sqare[1][1] = 1, sqare[1][2] = 1, sqare[1][3] = 0;
line = 0;
list = 3;
break;
case 4:
// ■
// ■ ■ ■
sqare[0][0] = 0, sqare[0][1] = 1, sqare[0][2] = 0, sqare[0][3] = 0;
sqare[1][0] = 1, sqare[1][1] = 1, sqare[1][2] = 1, sqare[1][3] = 0;
line = 0;
list = 3;
break;
case 5:
// ■ ■
// ■ ■
sqare[0][0] = 1, sqare[0][1] = 1, sqare[0][2] = 0, sqare[0][3] = 0;
sqare[1][0] = 1, sqare[1][1] = 1, sqare[1][2] = 0, sqare[1][3] = 0;
line = 0;
list = 4;
break;
case 6:
// ■ ■ ■ ■
sqare[0][0] = 1, sqare[0][1] = 1, sqare[0][2] = 1, sqare[0][3] = 1;
sqare[1][0] = 0, sqare[1][1] = 0, sqare[1][2] = 0, sqare[1][3] = 0;
line = 0;
list = 4;
break;
}
return sqareId;
}
判断能否移动,碰到地图边缘不能移动,碰到已经固定的方块不能移动:
// 判断方块是否能下落(落到最后一行就会停住)
bool Tetris::canSqareDown()
{
for (int i = 0; i < 10; ++i)
{
if (1 == background[19][i])
{
return false;
}
}
return true;
}
// 判断方块是否能下落(遇到已经固定的方块也会停住)
bool Tetris::canSqareDown2()
{
for (int i = 19; i >= 0; --i)
{
for (int j = 0; j < 10; ++j)
{
if (1 == background[i][j])
{
if (2 == background[i + 1][j])
{
return false;
}
}
}
}
return true;
}
bool Tetris::canSqareLeft();
bool Tetris::canSqareLeft2();
bool Tetris::canSqareRight();
bool Tetris::canSqareRight2();
判断是否能旋转:
// 判断方块是否能旋转
bool Tetris::canSqarechangeSqare()
{
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
if (2 == background[line + i][list + j])
{
return false;
}
}
}
if (list - 1 < 0)
{
list = 0; // 重置判断点
}
else if (list + 2 > 9)
{
list = 7;
}
return true;
}
// 判断直线是否能旋转
bool Tetris::canLineSqareChange()
{
// 太靠上或者太靠下都不让旋转
if (line >= 17 || line <= 1)
{
return false;
}
int i = 0, // 判断点与左右静止方块或边界的距离
j = 0;
for (i = 1; i < 4; ++i) // 获取判断点与右静止方块或边界的距离
{
if (2 == background[line][list + i] || list + i > 9)
{
break;
}
}
for (j = 1; j < 4; ++j) // 获取判断点与左静止方块或边界的距离
{
if (2 == background[line][list - j] || list - j < 0)
{
break;
}
}
if ((i - 1 + j - 1) < 3) // 判断是否有空间旋转
{
return false;
}
return true;
}
方块移动和旋转:
// 方块下落
void Tetris::sqareDown()
{
for (int i = 19; i >= 0; --i)
{
for (int j = 0; j < 10; ++j)
{
if (1 == background[i][j])
{
background[i + 1][j] = background[i][j];
background[i][j] = 0;
}
}
}
}
void Tetris::sqareLeft();
void Tetris::sqareRight();
// 旋转方块
void Tetris::changeSqare()
{
char arrSqare[3][3] = { {0} }; // 创建一个3*3的方块数组
// 把背景里的方块放进3*3的方块数组中
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
arrSqare[i][j] = background[line + i][list + j];
}
}
// 把3*3的方块数组旋转之后放进背景
int temp = 2;
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
{
background[line + i][list + j] = arrSqare[temp][i];
--temp;
}
temp = 2;
}
}
// 旋转直线
void Tetris::changeLineSqare()
{
if (1 == background[line][list - 1]) // 横着
{
background[line][list - 1] = 0;
background[line][list + 1] = 0;
background[line][list + 2] = 0;
if (2 == background[list + 1][list])
{
background[line - 1][list] = 0;
background[line - 2][list] = 0;
background[line - 3][list] = 0;
}
else if (2 == background[line + 2][list])
{
background[line + 1][list] = 0;
background[line - 1][list] = 0;
background[line - 2][list] = 0;
}
else
{
background[line - 1][list] = 1;
background[line + 1][list] = 1;
background[line + 2][list] = 1;
}
}
else // 竖着
{
background[line - 1][list] = 0;
background[line + 1][list] = 0;
background[line + 2][list] = 0;
if (2 == background[line][list + 1] || 9 == list)
{
background[line][list - 1] = 1;
background[line][list - 2] = 1;
background[line][list - 3] = 1;
list -= 2;
}
else if (2 == background[line][list + 2] || 8 == list)
{
background[line][list + 1] = 1;
background[line][list - 1] = 1;
background[line][list - 2] = 1;
--list;
}
else if (2 == background[line][list - 1] || 0 == list)
{
background[line][list + 1] = 1;
background[line][list + 2] = 1;
background[line][list + 3] = 1;
++list;
}
else
{
background[line][list - 1] = 1;
background[line][list + 1] = 1;
background[line][list + 2] = 1;
}
}
}
消除方块:
void Tetris::destoryOneLine()
{
int nsum = 0; // 一行的和
for (int i = 19; i >= 0; --i)
{
for (int j = 0; j < 10; ++j)
{
nsum += background[i][j];
}
if (20 == nsum)
{
for (int j = i - 1; j >= 0; --j)
{
for (int k = 0; k < 10; ++k)
{
background[j + 1][k] = background[j][k];
}
}
score += 10;
i = 20; // 再次从底部遍历
}
nsum = 0;
}
}
实现思路
-
按回车键开始游戏 创建一个定时器
LRESULT CALLBACK CallBack(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { 。。。 switch (nMsg) { case VK_RETURN: control.onReturn(hWnd); break; // 回车 。。。 } 。。。 } void Control::onReturn(HWND hWnd) { SetTimer(hWnd, DEF_TIME_ID, 500, NULL); gameStart = true; }
-
每隔0.5s重绘界面,用户有输入则移动方块,如果方块能下落则下落,否则固定方块,判断得分以及gameover,重新生成方块。
LRESULT CALLBACK CallBack(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { 。。。 switch (nMsg) { case VK_RETURN: control.onReturn(hWnd); break; // 回车 case VK_LEFT: control.onLeft(hWnd); break; // 左键 case VK_RIGHT: control.onRight(hWnd); break; // 右键 case VK_DOWN: control.onDown(hWnd); break; // 下键 case VK_UP: control.onUp(hWnd); break; // 上键 } 。。。 } void Control::onTimer(HWND hWnd) { HDC hdc = GetDC(hWnd); if (true == tetris.canSqareDown() && true == tetris.canSqareDown2()) { tetris.sqareDown(); tetris.addLine(); } else { tetris.change1To2(); tetris.destoryOneLine(); if (true == tetris.ifGameOver(hWnd)) { onClose(hWnd); Init(); return; } tetris.createRandSqare(); tetris.copySqareToBack(); } onPrint(hdc); ReleaseDC(hWnd, hdc); }
链接
百度云链接:https://pan.baidu.com/s/1SZDI5GhOcxDRrHZxnMec2g
提取码:p5mg