windows桌面程序: 俄罗斯方块 C++

先打开VS,创建解决方案
在这里插入图片描述
选择windows应用程序
在这里插入图片描述
在源文件文件夹下新建tetris.cpp文件,用来写我们实现俄罗斯方块的代码
代码及其注释如下所示:

/*
创建窗口
win32窗口的创建过程主要有6部分
1.头文件与主函数、2.创建窗口结构体、3.注册窗口、4.创建窗口、5.显示窗口、6.消息循环、7.回调函数
头文件:windows.h
主函数:int WINAPI WinMain( HINSTANCE hlnstance, //句柄:一个数,窗口唯一标识
HINSTANCE hPrevlnstance, //前一个句柄
LPTSTR lpCmdLine,//传递给应用程序的命令行参数
int nCmdShow)//指定窗口的显示方式 隐藏 最大最小显示
返回值:int
WINAPI:调用约定, 主要是参数的入栈顺序,这个栈空间的清理者,__stdcall,APIENTRY,本质都是一样的
WinMain:主函数的写法,注意不是main
*/

#include<time.h>
#include<stdlib.h>
#include<windows.h>

//定时器ID
#define DEF_TIMER1 1234

//创建兼容性DC
void OnPaint(HDC hDc);

//显示方块
void PaintSpare(HDC hMemDC);

//随机小方块
int CreateRandmSqare();

//随机小方块贴进背景
void CopySqareToBack();

//初始化
void OnCreate();

//回车键函数
void OnReturn(HWND hWnd);

//方块下落
void SqareDwon();

//定时器相应函数
void OnTimer(HWND hWnd);

//方块停在最底下 0 不可以下落 1可以下落
int CanSgareDown();

//下落
int CanSgareDown2();

//将1变成2
void Change1To2();

//显示2
void ShowSqare2(HDC hMemDC);

//左键
void OnLeft(HWND hWnd);

//左移
void SqareLeft();

//方块在最左面 0 不可以左移 1可以左移
int CanSgareLeft();

//左移限制
int CanSgareLeft2();

//右键
void OnRight(HWND hWnd);

//右移
void SqareRight();

//方块在最右面 0 不可以右移 1可以右移
int CanSgareRight();

//右移限制
int CanSgareRight2();

//加速向下
void OnDown(HWND hWnd);

//变形 上键
void OnUp(HWND hWnd);

//3 * 3变形
void ChangeSqare();

//3 * 3变形限制
int CanSqareChangeSape();

//长条变形
void ChangeLineSqare();

//长条变形限制
int CanLineSqareChange();

//消除已满的行数
void DestroyOneLineSqare();

//显示分数
void ShowScore(HDC hMemDC);

//游戏结束
int CanGomeOver();

//7.回调函数
// 回调函数 一个窗口对应一个窗口句柄
//long类型 调用约定 函数名字(窗口句柄,无符号整形消息的ID, 参数 3无符号整形 4long 传递信息自己定可以)
LRESULT CALLBACK PELouSi(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParan)
{
	PAINTSTRUCT pt;
	HDC hDC;//可以画的范围 也就是用户窗口可操作的范围(标识)
	switch (nMsg)
	{
	case WM_CREATE://窗口消息处理程序接收的第一个消息-也是回掉函数的第一个消息-是WM_CREATE 这个消息只产生一次,一般用于初始化一些数据
		OnCreate();
		break;
		//回掉函数的第二个消息
		//当窗口显示区域的一部分显示内容或者全部变为“无效”,以至于必须“更新画面”时,将由这个消息通知程序
		//窗口结构体的最后那个成员CS_HREDRAW | CS_VREDRAW,目的就是窗口大小发生变化的时候,产生WM_PAINT消息
		//窗口重叠时,重叠部分渐渐出现时

	case WM_TIMER://定时器消息
		OnTimer(hWnd);
		break;

	case WM_PAINT:
		hDC = BeginPaint(hWnd, &pt);//画窗口内容开始 有用getDC的
		OnPaint(hDC);//画图的函数
		EndPaint(hWnd, &pt);//画窗口内容结束
		break;

	case WM_KEYDOWN://WM_KEYDOWN键盘安下
		switch (wParam)//wParam回掉函数第三个参数 区分是按得那个键
		{
		case VK_RETURN://回车键
			OnReturn(hWnd);//开始
			break;

		case VK_LEFT://左键
			OnLeft(hWnd);//左移
			break;

		case VK_RIGHT://右键
			OnRight(hWnd);//右移
			break;

		case VK_UP://上键
			OnUp(hWnd);//变形
			break;

		case VK_DOWN://下键
			OnDown(hWnd);//加速
			break;
		}
		break;

	case WM_DESTROY://点×三种消息依次产生: WM_CLOSE -> WM_DESTROY销毁窗口 -> WM_QUIT退出消息 W:windows M:消息
		KillTimer(hWnd, DEF_TIMER1);
		PostQuitMessage(0);//传递退出消息
		break;
	}
	return DefWindowProc(hWnd, nMsg, wParam, lParan);//功能 没有处理的消息系统自动处理 保证系统的连贯性 什么都不做 每次在窗口有点击、输入都会有消息
}

//1.头文件与主函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	//2.创建窗口结构体
	//初始化窗口类

	WNDCLASSEX wc;
	HWND hWnd;
	MSG mSg; //MSG 消息的结构体

	//12个成员不能多不能少 要不 失败
	wc.cbClsExtra = 0;//紧跟在窗口类尾部的一块额外的空间,不用设为0。
	wc.cbSize = sizeof(WNDCLASSEX);//类的大小
	wc.cbWndExtra = 0;//拓展窗口对话框
	wc.hbrBackground = (HBRUSH)COLOR_SCROLLBAR;//背景颜色COLOR_BACKGROUND
	wc.hCursor = NULL;//光标样式 LoadCursor(句柄系统定义填NULL 加载自定义填hInstance,样式 自定义添加资源文件)
	wc.hIcon = NULL;//任务栏显示的图标 LoadIcon(句柄系统定义填NULL 加载自定义填hInstance,样式 自定义添加资源文件)
	wc.hIconSm = NULL;//窗口左上角的图标 如果为空则默认为任务栏的图标
	wc.hInstance = hInstance;//当前窗口的句柄 //句柄又系统传递
	wc.lpfnWndProc = PELouSi;//回掉函数函数地址
	wc.lpszClassName = L"elsfk";//窗口类的名字 名字不要重复 给系统看的 不是最上面那个名字
	wc.lpszMenuName = NULL; //菜单
	wc.style = CS_HREDRAW | CS_VREDRAW;///窗口显示风格 垂直刷新 水平刷新 最大化等

	//3.注册窗口对象
	if (0 == RegisterClassEx(&wc))//如果注册失败
	{
		//出错 不知道什么原因
		int a = GetLastError();//用这个函数 返回一个值
		return 0;
	}

	//4.创建窗口
	hWnd = CreateWindowEx(WS_EX_TOPMOST, L"elsfk", L"俄罗斯方块", WS_OVERLAPPEDWINDOW, 100, 100, 500, 646, NULL, NULL, hInstance, NULL);

	//(附加属性 (WS_EX_TOPMOST总是在最前端),
	//窗口类的名字 名字不要重复 给系统看的 不是最上面那个名字 与上面的一样,
	//窗口的名字 左上角的 人你看的... ,
	//指定窗口的风格,
	//int x;相对于桌面 坐标 是像素 左,
	//int y;相对于桌面 坐标 是像素 上,
	//宽度,
	//高度,
	//子句柄 子窗口,
	//菜单的句柄 没有菜单NULL,
	//当前实例句柄,
	//(win下lp是指针类型)指向一个值得指针,多文档 多个编辑框);
	if (NULL == hWnd) //窗口句柄 窗口的唯一标识
	{
		return 0;
	}

	//5.显示窗口
	ShowWindow(hWnd, SW_SHOWNORMAL);//句柄,显示风格(最大化 最小化 默认nCmdShow等)
	//隐藏显示返回0 正常显示返回非0

	//6.消息循环
	while (GetMessage(&mSg, NULL, 0, 0))//(指向MSG消息结构体的指针,窗口句柄(NULL与非NULL的区别NULL接收所以窗口消息非NULL接所填句柄的消息,3 4参数处理消息范围(0, 0是取所以范围))
	//GetMessage取到消息返回非零值
	{
		//消息翻译 将输入设备的电信号转换成字符消息
		TranslateMessage(&mSg);//参是一个指针指向结构体
		//分发消息 分类 :标准消息 命令消息 通知消息 自定义消息
		DispatchMessage(&mSg);//参是一个指针指向结构体
	}
	return 0;
}

/*
兼容性DC(就是在后台画好当前页面再给当前)
创建兼容性DC
HDC CreateCompatibleDC(HDC hdc);
创建兼容性位图
HBITMAP CreateCompatibleBitmap(HDC hdc, int nWidth, int nHeight);
将DC与位图绑定在一起
HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj);
释放DC
BOOL DeleteDC(HDC hdc);
将内存DC传递到窗口DC
BOOL BitBlt(HDC hdcDest, int nXDest, int nYDest, nt nWidth, int nHeight, HDC hdcSrc, int nXSrc, int nYSrc, DWORD dwRop);
(目标DC 窗口DC, 2 3参数 目标的起始位置 注意是基于我们的窗口, 4 5区域的大小, 源DC 也是我们的内存DC, 7 8内存图片的起始位置, 传递的方式)
返回值:失败返回0,成功返回非0
*/

/*
定时器:
启动定时器
UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc);
(窗口句柄hWnd NULL, 定时器ID 不理会, 间隔时间 毫秒 1000ms = 1s, 设置为NULL 处理函数的地址);
返回值:成功返回非零
关闭定时器
BOOL KillTimer(HWND hWnd, UINT_PTR uIDEvent);
*/

/*
给方块图色
HBRUSH oldBrush;
创建一个颜色的画刷
HBRUSH newBrush = CreateSolidBrush(RGB(67, 132, 19));
绑定当前DC与画刷,返回系统默认画刷
oldBrush = SelectObject(hdc, newBrush);
使用完新画刷,把系统默认画刷选回来,返回创建的画刷
newBrush = SelectObject(hdc,oldBrush);
释放画刷句柄
DeleteObject(newBrush);
*/

//背景数组(二维数组)
char g_arrBackGroud[20][10] = { 0 };

//小方块数组
char g_arrSqare[2][4] = { 0 };

//标记小方块的形状
int g_nSqareID = -1;

// 记录位置
int g_nLine = -1;//行
int g_nList = -1;//列

//记分
int g_nScore = 0;

//函数实现
void OnPaint(HDC hDc)
{
	//创建兼容性DC(dc编号)可以创建多个
	HDC hMemDC = CreateCompatibleDC(hDc);
	//位图(创建一张纸)
	HBITMAP hBitmapBack = CreateCompatibleBitmap(hDc, 500, 646);//(,纸的大小)
	//关联起来
	SelectObject(hMemDC, hBitmapBack);
	//显示方块
	PaintSpare(hMemDC);
	ShowSqare2(hMemDC);
	//显示右面 显示分数
	ShowScore(hMemDC);
	//传递//源
	BitBlt(hDc, 0, 0, 500, 600, hMemDC, 0, 0, SRCCOPY);
	//释放DC
	DeleteObject(hBitmapBack);//位图
	DeleteDC(hMemDC);//编号
}

//显示分数
void ShowScore(HDC hMemDC)
{
	char strScore[10] = { 0 };
	Rectangle(hMemDC, 300, 0, 500, 646);//右边显示
	itoa(g_nScore, strScore, 10);//转换成字符串
	TextOut(hMemDC, 340, 100, L"得分:", strlen("得分:"));
	TextOut(hMemDC, 400, 100, (LPCWSTR)strScore, strlen(strScore));//(句柄,x,y,一个字符串,字节数 有效的)
	TextOut(hMemDC, 340, 180, L"回车开始", strlen("回车开始"));
	TextOut(hMemDC, 340, 210, L"上键变形", strlen("上键变形"));
	TextOut(hMemDC, 340, 240, L"下键加速", strlen("下键加速"));
	TextOut(hMemDC, 340, 270, L"左键左移", strlen("左键左移"));
	TextOut(hMemDC, 340, 300, L"右键右移", strlen("右键右移"));
	TextOut(hMemDC, 350, 150, L"按键:", strlen("按键:"));
}

//初始化
void OnCreate()
{
	srand((unsigned)time(NULL));
	CreateRandmSqare();
	CopySqareToBack();
}

//显示方块
void PaintSpare(HDC hMemDC)
{
	int i = 0;
	int j = 0;//i j 循环遍历用
	//旧的画刷
	HBRUSH hOldBrush;
	//画刷 涂颜色
	HBRUSH hNewBrush;
	//画刷 涂颜色背景
	hNewBrush = CreateSolidBrush(RGB(255, 255, 128));
	//选入当前DC
	hOldBrush = (HBRUSH)SelectObject(hMemDC, hNewBrush);
	//画大方块
	Rectangle(hMemDC, 0, 0, 300, 600);//(画板, 画窗口起始位置, 画结束位置 先横向 后竖向)
	hNewBrush = (HBRUSH)SelectObject(hMemDC, hOldBrush);
	DeleteObject(hNewBrush);
	hNewBrush = CreateSolidBrush(RGB(0, 255, 0));
	//选入当前DC
	hOldBrush = (HBRUSH)SelectObject(hMemDC, hNewBrush);
	//遍历
	for (i = 0; i < 20; i++)//行
	{
		for (j = 0; j < 10; j++)//列
		{
			if (1 == g_arrBackGroud[i][j])
			{
				//画方块
				Rectangle(hMemDC, j * 30, i * 30, j * 30 + 30, i * 30 + 30);
			}
		}
	}
	hNewBrush = (HBRUSH)SelectObject(hMemDC, hOldBrush);
	DeleteObject(hNewBrush);
}

//随机小方块
int CreateRandmSqare()
{
	int n = rand() % 7;
	switch (n)//n
	{
		case 1:
		g_arrSqare[0][0] = 1,g_arrSqare[0][1] = 1, g_arrSqare[0][2] = 0, g_arrSqare[0][3] = 0;
		g_arrSqare[1][0] = 0, g_arrSqare[1][1] = 1, g_arrSqare[1][2] = 1, g_arrSqare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;

		case 2:
		g_arrSqare[0][0] = 0,g_arrSqare[0][1] = 1, g_arrSqare[0][2] = 1, g_arrSqare[0][3] = 0;
		g_arrSqare[1][0] = 1, g_arrSqare[1][1] = 1, g_arrSqare[1][2] = 0, g_arrSqare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;

		case 3:
		g_arrSqare[0][0] = 1,g_arrSqare[0][1] = 1, g_arrSqare[0][2] = 1, g_arrSqare[0][3] = 0;
		g_arrSqare[1][0] = 1, g_arrSqare[1][1] = 0, g_arrSqare[1][2] = 0, g_arrSqare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;

		case 4:
		g_arrSqare[0][0] = 1, g_arrSqare[0][1] = 0, g_arrSqare[0][2] = 0, g_arrSqare[0][3] = 0;
		g_arrSqare[1][0] = 1, g_arrSqare[1][1] = 1, g_arrSqare[1][2] = 1, g_arrSqare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;

		case 5:
		g_arrSqare[0][0] = 0, g_arrSqare[0][1] = 1, g_arrSqare[0][2] = 1, g_arrSqare[0][3] = 0;
		g_arrSqare[1][0] = 0, g_arrSqare[1][1] = 1, g_arrSqare[1][2] = 1, g_arrSqare[1][3] = 0;
		break;

		case 6:
		g_arrSqare[0][0] = 1, g_arrSqare[0][1] = 1, g_arrSqare[0][2] = 1, g_arrSqare[0][3] = 1;
		g_arrSqare[1][0] = 0, g_arrSqare[1][1] = 0, g_arrSqare[1][2] = 0, g_arrSqare[1][3] = 0;
		g_nLine = 0;
		g_nList = 4;
		break;

		case 0:
		g_arrSqare[0][0] = 0, g_arrSqare[0][1] = 1, g_arrSqare[0][2] = 0, g_arrSqare[0][3] = 0;
		g_arrSqare[1][0] = 1, g_arrSqare[1][1] = 1, g_arrSqare[1][2] = 1, g_arrSqare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;
	}
	//小方块的ID
	g_nSqareID = n;
	return n;
}

//随机小方块贴进背景
void CopySqareToBack()
{
	int i = 0;
	int j = 0;
	for (i = 0; i < 2; i++)
	{
		for (j = 0; j < 4; j++)
		{
			g_arrBackGroud[i][j + 3] = g_arrSqare[i][j];
		}
	}
}

//回车键函数
void OnReturn(HWND hWnd)
{
	//打开定时器
	SetTimer(hWnd, DEF_TIMER1, 600, NULL);
}

//方块下落
void SqareDwon()
{
	int i = 0;
	int j = 0;
	for (i = 19; i >= 0; i--)
	{
		for (j = 0; j < 10; j++)
		{
			if (1 == g_arrBackGroud[i][j])
			{
				g_arrBackGroud[i + 1][j] = g_arrBackGroud[i][j];
				g_arrBackGroud[i][j] = 0;
			}
		}
	}
}

//定时器相应函数
void OnTimer(HWND hWnd)
{
	//得到DC的函数
	HDC hDc = GetDC(hWnd);
	//判断是否能下落
	if (1 == CanSgareDown() && 1 == CanSgareDown2())
	{
		//方块下落
		SqareDwon();
		g_nLine++;
	}
	else
	{
		//1变成2
		Change1To2();
		//消除已满的行数
		DestroyOneLineSqare();
		//游戏结束
		if (0 == CanGomeOver())
		{
			//结束
			KillTimer(hWnd, DEF_TIMER1);
			return ;
		}
		//产生随机块
		CreateRandmSqare();
		//复制到背景上
		CopySqareToBack();
	}
	//显示方块
	//PaintSpare(hDc);
	OnPaint(hDc);
	//释放DC
	ReleaseDC(hWnd, hDc);//内核对象 要程序员释放
}

//方块停在最底下 0 不可以下落 1可以下落
int CanSgareDown()
{
	for (int i = 0; i < 10; i++)
	{
		if (1 == g_arrBackGroud[19][i])
		{
			return 0;
		}
	}
	return 1;
}

//将1变成2
void Change1To2()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (1 == g_arrBackGroud[i][j])
			{
				g_arrBackGroud[i][j] = 2;
			}
		}
	}
}

//显示2
void ShowSqare2(HDC hMemDC)
{
	//旧的画刷
	HBRUSH hOldBrush;
	//画刷 涂颜色
	HBRUSH hNewBrush = CreateSolidBrush(RGB(109, 249, 252));
	//选入当前DC
	hOldBrush = (HBRUSH)SelectObject(hMemDC, hNewBrush);
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (2 == g_arrBackGroud[i][j])
			{
				Rectangle(hMemDC, j * 30, i * 30, j * 30 + 30, i * 30 + 30);
			}
		}
	}
	hNewBrush = (HBRUSH)SelectObject(hMemDC, hOldBrush);
	DeleteObject(hNewBrush);
}

//下落
int CanSgareDown2()
{
	for (int i = 19; i >= 0; i--)
	{
		for (int j = 0; j < 10; j++)
		{
			if (1 == g_arrBackGroud[i][j] && 2 == g_arrBackGroud[i + 1][j])
			{
				return 0;
			}
		}
	}
	return 1;
}

//左键
void OnLeft(HWND hWnd)
{
	//方块向左移
	if (1 == CanSgareLeft() && 1 == CanSgareLeft2())
	{
		//得到DC的函数
		HDC hDc = GetDC(hWnd);
		g_nList--;
		SqareLeft();
		//显示方块
		OnPaint(hDc);
		//释放DC
		ReleaseDC(hWnd, hDc);
	}
}

//左移
void SqareLeft()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (1 == g_arrBackGroud[i][j])
			{
				g_arrBackGroud[i][j - 1] = g_arrBackGroud[i][j];
				g_arrBackGroud[i][j] = 0;
			}
		}
	}
}

//方块在最左面 0 不可以左移 1可以左移
int CanSgareLeft()
{
	for (int i = 0; i < 20; i++)
	{
		if (1 == g_arrBackGroud[i][0])
		{
			return 0;
		}
	}
	return 1;
}

//左移限制
int CanSgareLeft2()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (1 == g_arrBackGroud[i][j] && 2 == g_arrBackGroud[i][j - 1])
			{
				return 0;
			}
		}
	}
	return 1;
}

//右键
void OnRight(HWND hWnd)
{
	//右移
	if (1 == CanSgareRight() && 1 == CanSgareRight2())
	{
		//得到一个DC函数
		HDC hDc = GetDC(hWnd);
		g_nList++;
		SqareRight();
		//显示方块
		OnPaint(hDc);
		//释放DC
		ReleaseDC(hWnd, hDc);
	}
}

//右移
void SqareRight()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 9; j >= 0; j--)
		{
			if (1 == g_arrBackGroud[i][j])
			{
				g_arrBackGroud[i][j + 1] = g_arrBackGroud[i][j];
				g_arrBackGroud[i][j] = 0;
			}
		}
	}
}

//方块在最右面 0 不可以右移 1可以右移
int CanSgareRight()
{
	for (int i = 0; i < 20; i++)
	{
		if (1 == g_arrBackGroud[i][19])
		{
			return 0;
		}
	}
	return 1;
}

//右移限制
int CanSgareRight2()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (1 == g_arrBackGroud[i][j] && 2 == g_arrBackGroud[i][j + 1])
			{
				return 0;
			}
		}
	}
	return 1;
}

//加速向下
void OnDown(HWND hWnd)
{
	OnTimer(hWnd);
}

//变形 上键
void OnUp(HWND hWnd)
{
	HDC hDc = GetDC(hWnd);
	switch (g_nSqareID)//g_nSqareID
	{
		case 0:

		case 1:

		case 2:

		case 3:

		case 4://普通变形
			if (1 == CanSqareChangeSape())//3 * 3变形限制
			{
				ChangeSqare();//3 * 3变形
			}
			else
			{
				return;
			}
			break;

		case 5:// 正方形
			return;
			break;

		case 6://长条形
			if (1 == CanLineSqareChange())//长条变形限制
			{
				ChangeLineSqare();//长条变形
			}
			break;
	}
	//显示
	OnPaint(hDc);
}

//3 * 3变形
void ChangeSqare()
{
	int nTemp = 2;
	//用于交换的小方块
	char arrSqare[3][3] = { 0 };
	//小方块复制出来
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			arrSqare[i][j] = g_arrBackGroud[g_nLine + i][g_nList + j];
		}
	}
	//变形后复制回去
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			g_arrBackGroud[g_nLine + i][g_nList + j] = arrSqare[nTemp][i];
			nTemp--;
		}
		nTemp = 2;
	}
}

//3 * 3变形限制
int CanSqareChangeSape()
{
	//限制与其他小方块连在一起变形
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (2 == g_arrBackGroud[g_nLine + i][g_nList + j])
			{
				return 0;
			}
		}
	}
	//限制超出边境变形
	/*if (g_nList < 0 || g_nList + 2 > 9) 第一种不好有些限制不能进行变形
	{
	return 0;
	}*/
	if (g_nList < 0)
	{
		g_nList = 0;
	}
	else if (g_nList + 2 > 9)
	{
		g_nList = 7;
	}
	return 1;
}

//长条变形

void ChangeLineSqare()
{
	if (1 == g_arrBackGroud[g_nLine][g_nList - 1])//横的出现
	{
		//清零
		g_arrBackGroud[g_nLine][g_nList - 1] = 0;
		g_arrBackGroud[g_nLine][g_nList + 1] = 0;
		g_arrBackGroud[g_nLine][g_nList + 2] = 0;
		if (2 == g_arrBackGroud[g_nLine + 1][g_nList])
		{
			//赋值
			g_arrBackGroud[g_nLine - 1][g_nList] = 1;
			g_arrBackGroud[g_nLine - 2][g_nList] = 1;
			g_arrBackGroud[g_nLine - 3][g_nList] = 1;
		}

		else if (2 == g_arrBackGroud[g_nLine + 2][g_nList])
		{
			//赋值
			g_arrBackGroud[g_nLine + 1][g_nList] = 1;
			g_arrBackGroud[g_nLine - 1][g_nList] = 1;
			g_arrBackGroud[g_nLine - 2][g_nList] = 1;
		}
		else
		{
			//赋值
			g_arrBackGroud[g_nLine - 1][g_nList] = 1;
			g_arrBackGroud[g_nLine + 1][g_nList] = 1;
			g_arrBackGroud[g_nLine + 2][g_nList] = 1;
		}
	}
	else//竖的出现
	{
		//清零
		g_arrBackGroud[g_nLine - 1][g_nList] = 0;
		g_arrBackGroud[g_nLine + 1][g_nList] = 0;
		g_arrBackGroud[g_nLine + 2][g_nList] = 0;
		if (2 == g_arrBackGroud[g_nLine][g_nList + 1] || 9 == g_nList)
		{
			//赋值
			g_arrBackGroud[g_nLine][g_nList - 1] = 1;
			g_arrBackGroud[g_nLine][g_nList - 2] = 1;
			g_arrBackGroud[g_nLine][g_nList - 3] = 1;
			//标记改变
			g_nList = g_nList - 2;
		}
		else if (2 == g_arrBackGroud[g_nLine][g_nList + 2] || 8 == g_nList)
		{
			//赋值
			g_arrBackGroud[g_nLine][g_nList + 1] = 1;
			g_arrBackGroud[g_nLine][g_nList - 1] = 1;
			g_arrBackGroud[g_nLine][g_nList - 2] = 1;
			//标记改变
			g_nList = g_nList - 1;
		}
		else if (2 == g_arrBackGroud[g_nLine][g_nList - 1] || 0 == g_nList)
		{
			//赋值
			g_arrBackGroud[g_nLine][g_nList + 1] = 1;
			g_arrBackGroud[g_nLine][g_nList + 3] = 1;
			g_arrBackGroud[g_nLine][g_nList + 2] = 1;
			//标记改变
			g_nList = g_nList + 1;
		}
		else
		{
			//赋值
			g_arrBackGroud[g_nLine][g_nList - 1] = 1;
			g_arrBackGroud[g_nLine][g_nList + 1] = 1;
			g_arrBackGroud[g_nLine][g_nList + 2] = 1;
		}
	}
}

//长条变形限制
int CanLineSqareChange()
{
	int i = 0, j = 0;
	for (i = 1; i < 4; i++)
	{
		if (2 == g_arrBackGroud[g_nLine][g_nList + i] || g_nList + i > 9)
		{
			break;
		}
	}
	for (j = 1; j < 4; j++)
	{
		if (2 == g_arrBackGroud[g_nLine][g_nList - j] || g_nList - j < 0)
		{
			break;
		}
	}
	if ((i - 1 + j - 1) < 3)
	{
		return 0;
	}
	return 1;
}

//消除已满的行数
void DestroyOneLineSqare()
{
	int i = 0, j = 0;
	int nSum = 0;
	int nTempi = 0;
	for (i = 19; i >= 0; i--)
	{
		for (j = 0; j < 10; j++)
		{
			nSum += g_arrBackGroud[i][j];
		}
		if (20 == nSum)
		{
			//消除一行
			for (nTempi = i - 1; nTempi >= 10; nTempi--)
			{
				for (j = 0; j < 10; j++)
				{
					g_arrBackGroud[nTempi + 1][j] = g_arrBackGroud[nTempi][j];
				}
			}
			//记分用
			g_nScore++;
			//为了能消除多行
			i = 20;
		}
		//清零
		nSum = 0;
	}
}

//游戏结束

int CanGomeOver()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		if (2 == g_arrBackGroud[0][i])
		{
			//游戏结束
			MessageBox(NULL, L"游戏结束", L"提示", MB_OK);//消息盒子(句柄 可写可不写,字符串指针 内容, 字符串指针, 风格)
			return 0;
		}
	}
	return 1;
}

接下来我们来玩一玩这个游戏
点击调试
在这里插入图片描述
按回车键开启计时器

开始游戏
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一切工作正常
在这里插入图片描述
那么今天的教程就到这里了

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值