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

接下來我們來玩一玩這個遊戲
點擊調試
在這裏插入圖片描述
按回車鍵開啓計時器

開始遊戲
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
一切工作正常
在這裏插入圖片描述
那麼今天的教程就到這裏了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章