1. 程式人生 > >WIN32 俄羅斯方塊

WIN32 俄羅斯方塊

WIN32 主程式

#include<Windows.h>
#include"Tetris.h"


LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);      // 回撥函式

// WINAPI 呼叫約定
// 當前視窗控制代碼 HINSTANCE hInstance
// 前一個視窗控制代碼 HINSTANCE hPreInstance
// 指定命令列引數 LPTSTR lpCmdLine
// 視窗顯示方式
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR lpCmdLine, int nCmdShow)
{
	WNDCLASSEX wc;                           // 初始化視窗類
	wc.cbClsExtra = 0;
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)COLOR_WINDOW; // 視窗背景顏色
	wc.hCursor = NULL;                       // 滑鼠游標
	wc.hIcon = NULL;                         // 視窗大圖示
	wc.hIconSm = NULL;                       // 視窗的小圖示
	wc.hInstance = hInstance;                // 視窗控制代碼
	wc.lpfnWndProc = WndProc;                // 回撥函式地址
	wc.lpszClassName = "Tetris";             // 視窗名字,給作業系統看的
	wc.lpszMenuName = NULL;                  // 選單名字
	wc.style = CS_HREDRAW | CS_VREDRAW;      // 視窗風格(垂直重新整理和水平重新整理)

	// 12個成員
	

	if (RegisterClassEx(&wc) == 0)              // 註冊視窗物件
		return 0;
	HWND hWnd = CreateWindowEx(WS_EX_TOPMOST,"Tetris", "俄羅斯方塊",
		WS_OVERLAPPEDWINDOW,100,100,500,650,NULL,
		NULL, hInstance,NULL);                  // 建立視窗
	if (hWnd == NULL)
		return 0;

	ShowWindow(hWnd, nCmdShow);                 // 顯示視窗
		
	MSG mSg;                                    // 訊息結構體
	
	while (GetMessage(&mSg, NULL, 0, 0))        // 訊息迴圈
	{
		TranslateMessage(&mSg);                 // 翻譯訊息
		DispatchMessage(&mSg);                  // 分發訊息
	}
	
	return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)       // 回撥函式
{
	PAINTSTRUCT pt;
	HDC hDC;          
	switch (nMsg)
	{
	case WM_CREATE:   // 視窗建立初期只產生一次、
		// 初始化資料
		OnCreate();
		break;

	case WM_PAINT:
		hDC = BeginPaint(hWnd,&pt);       // 視窗可操作區域的標識
		OnPaint(hDC);                     // 繪製介面

		EndPaint(hWnd, &pt);
		break;

	case WM_TIMER:
		OnTimer(hWnd);                    // 定時器相應函式
		break;

	case WM_KEYDOWN:
		switch (wParam)
		{
		case VK_RETURN:
			OnReturn(hWnd);                      // 回車響應函式
			break;
		case VK_LEFT:
			OnLeft(hWnd);                        // 左鍵響應函式
			break;
		case VK_RIGHT:
			OnRight(hWnd);                       // 右鍵響應函式
			break;
		case VK_UP:
			OnChangeSquare(hWnd);                // 上鍵響應函式
			break;
		case VK_DOWN:                            // 下鍵響應函式
			OnDown(hWnd);
			break;
		}
		break;

	case WM_DESTROY:
		KillTimer(hWnd, DEF_TIMER);                      // 關閉定時器
		PostQuitMessage(0);
		break;


	}
	return DefWindowProc(hWnd, nMsg, wParam, lParam);     // 讓系統自動處理一些訊息
}

俄羅斯方塊宣告函式

#pragma once
#include<Windows.h>
#include<stdio.h>
#include<time.h>

#define DEF_TIMER 1234        // 定時器id

void OnPaint(HDC hDc);          //  顯示介面
void PaintSquare(HDC hDc);      //  畫方塊
void CreateRandomSquare();      // 建立隨機塊
void CopySquareToBack();        // 隨機快貼背景
void Change1To2();              // 方塊落到最底部將1變為2
void ShowSquare2(HDC  hMemDC);  // 顯示底部方塊


void OnCreate();                // 建立背景隨機塊
void OnReturn(HWND hWnd);       // 處理回車按鍵
void OnTimer(HWND hWnd);        // 定時器響應函式
void OnLeft(HWND hWnd);         // 處理左鍵
void OnRight(HWND hWnd);        // 處理右鍵
void OnDown(HWND hWnd);         // 處理下鍵
void OnChangeSquare(HWND hWnd); // 處理按上鍵方塊變形


int CanSquareDown();           // 0代表方塊不可以下落,1代表方塊可以下落
int CanSquareDown2();          // 方塊下落遇到障礙判斷
int CanSquareLeft();           // 判斷方塊是否能左移
int CanSquareLeft2();          // 判斷方塊向左移動與存在方塊碰撞
int CanSquareRight();          // 判斷方塊與右牆壁的碰撞
int CanSquareRight2();         // 檢查方塊與右方塊的碰撞
int CanSquareChangeShape();    // 判斷方塊是否能變形
int CanLineSquareChange();     // 判斷長條是否能變形


void SquareDown();             // 方塊下落
void SquareLeft();             // 方塊左移
void SquareRight();            // 方塊右動

void ChangeSquare();           // 方塊變形函式
void ChangeLineSquare();       // 長條變形
void DestroyOneLineSquare();   // 消除一行方塊
void ShowScore(HDC hHemDC);    // 顯示分數
int CanGameOver();             // 遊戲結束彈窗

 

具體函式實現

#include "Tetris.h"


char g_arrBackGround[20][10] = { 0 };                   // 背景陣列
char g_arrSquare[2][4] = { 0 };                         // 方塊型別的小陣列
int g_nSquareID;                                        // 方塊的型別編號
int g_nLine = -1;                                       // 方塊包圍盒的左上角行
int g_nList = -1;                                       // 方塊包圍盒的左上角列
int g_nScore = 0;                                       // 計分

void OnPaint(HDC hDc)
{
	HDC hMemDC = CreateCompatibleDC(hDc);               // 建立相容性DC
	HBITMAP hBitmapBack = CreateCompatibleBitmap(hDc, 500, 600);    // 建立一張紙
	SelectObject(hMemDC, hBitmapBack);                     // 視窗和紙關聯在一起

	PaintSquare(hMemDC);                                // 畫方塊
	ShowSquare2(hMemDC);                                // 落到底部的方塊,畫顏色
	ShowScore(hMemDC);                                  // 介面顯示分數
	BitBlt(hDc, 0, 0, 500, 600, hMemDC, 0, 0, SRCCOPY); // 記憶體DC複製到視窗
	

	DeleteObject(hBitmapBack);                          // 釋放記憶體
	DeleteDC(hMemDC);
}

void OnCreate()
{
	srand((unsigned int)time(NULL));                   // 當前系統時間作為隨機數種子
	CreateRandomSquare();                              // 建立隨機方塊
	CopySquareToBack();                                // 將隨機方塊貼到背景
}

void PaintSquare(HDC hMemDC)
{
	Rectangle(hMemDC, 0, 0, 300, 600);                  // 畫矩形框    

	HGDIOBJ hOldBrush;
	HGDIOBJ hNewBrush = CreateSolidBrush(RGB(63, 191, 49));
	hOldBrush = SelectObject(hMemDC, hNewBrush);
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBackGround[i][j] == 1)
			{
				Rectangle(hMemDC, j * 30, i * 30, (j + 1) * 30, (i + 1) * 30);
			}
		}
	}
	hNewBrush = SelectObject(hMemDC, hOldBrush);
	DeleteObject(hNewBrush);

}

void CreateRandomSquare()
{
	int n;
	n = rand() % 7;
	switch (n)
	{
	case 0:
		g_arrSquare[0][0] = 1, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 0, g_arrSquare[0][3] = 0;
		g_arrSquare[1][0] = 0, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;
	case 1:
		g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 0;
		g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 0, g_arrSquare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;
	case 2:
		g_arrSquare[0][0] = 1, g_arrSquare[0][1] = 0, g_arrSquare[0][2] = 0, g_arrSquare[0][3] = 0;
		g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;
	case 3:
		g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 0, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 0;
		g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;
	case 4:
		g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 0, g_arrSquare[0][3] = 0;
		g_arrSquare[1][0] = 1, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
		g_nLine = 0;
		g_nList = 3;
		break;
	case 5:
		g_arrSquare[0][0] = 0, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 0;
		g_arrSquare[1][0] = 0, g_arrSquare[1][1] = 1, g_arrSquare[1][2] = 1, g_arrSquare[1][3] = 0;
		g_nLine = 0;
		g_nList = 4;
		break;
	case 6:
		g_arrSquare[0][0] = 1, g_arrSquare[0][1] = 1, g_arrSquare[0][2] = 1, g_arrSquare[0][3] = 1;
		g_arrSquare[1][0] = 0, g_arrSquare[1][1] = 0, g_arrSquare[1][2] = 0, g_arrSquare[1][3] = 0;
		g_nLine = 0;
		g_nList = 4;
		break;
	}

	g_nSquareID = n;

}

void CopySquareToBack()
{
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			g_arrBackGround[i][j+3] = g_arrSquare[i][j];
		}
	}
}

void OnReturn(HWND hWnd)
{
	SetTimer(hWnd, DEF_TIMER, 400, NULL);       // 直接呼叫定時器函式
}

void SquareDown()
{
	for (int i = 19; i >= 0; i--)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBackGround[i][j] == 1)
			{
				g_arrBackGround[i + 1][j] = g_arrBackGround[i][j];
				g_arrBackGround[i][j] = 0;
			}
		}
	}
}

void OnTimer(HWND hWnd)
{
	HDC hDc = GetDC(hWnd);
	if (CanSquareDown() == 1 && CanSquareDown2() == 1)
	{
		SquareDown();             // 如果方塊能下落,方塊下落
		g_nLine++;
	}
	else
	{              
		Change1To2();             // 當方塊落到底部時,將1變為2
		DestroyOneLineSquare();   // 消除方塊
		if (CanGameOver() == 0)
		{
			KillTimer(hWnd, DEF_TIMER);
			return;
		}
		CanGameOver();            // 判斷遊戲結束
		CreateRandomSquare();     // 如果方塊落到底部,產生新的方塊
		CopySquareToBack();
	}
       
	OnPaint(hDc);
	ReleaseDC(hWnd, hDc);  // 釋放

}

int CanSquareDown()
{
	for (int i = 0; i < 10; i++)
	{
		if (g_arrBackGround[19][i] == 1)
		{
			return 0;
		}
	}
	return 1;
}

void Change1To2()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBackGround[i][j] == 1)
			{
				g_arrBackGround[i][j] = 2;
			}
		}
	}
}

void ShowSquare2(HDC  hMemDC)
{
	HGDIOBJ hOldBrush;
	HGDIOBJ hNewBrush = CreateSolidBrush(RGB(233, 27, 182));  // 建立一個畫刷
	hOldBrush = SelectObject(hMemDC, hNewBrush);
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBackGround[i][j] == 2)
			{
				Rectangle(hMemDC, j * 30, i * 30, (j + 1) * 30, (i + 1) * 30);
			}
		}
	}
	hNewBrush = SelectObject(hMemDC, hOldBrush);
	DeleteObject(hNewBrush);
}

int CanSquareDown2()
{
	for (int i = 19; i >=0; i--)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBackGround[i][j] == 1 && g_arrBackGround[i+1][j] == 2)
			{
				return 0;
			}
		}
	}
	return 1;
}

void OnLeft(HWND hWnd)
{
	
	if (CanSquareLeft() == 1 && CanSquareLeft2()==1)
	{
		HDC hDc = GetDC(hWnd);
		SquareLeft();          // 方塊向左移
		g_nList--;
		OnPaint(hDc);
		ReleaseDC(hWnd, hDc);
	}
	
}

void SquareLeft()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBackGround[i][j] == 1)
			{
				g_arrBackGround[i][j-1] = g_arrBackGround[i][j];
				g_arrBackGround[i][j] = 0;
			}
		}
	}
}

int CanSquareLeft()
{
	for (int i = 0; i < 20; i++)
	{
		if (1 == g_arrBackGround[i][0])
		{
			return 0;
		}
	}
	return 1;
}

int CanSquareLeft2()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBackGround[i][j] == 1 && g_arrBackGround[i][j - 1] == 2)
				return 0;
		}
	}
	return 1;
}

void OnRight(HWND hWnd)
{
	
	
	if (CanSquareRight() == 1 && CanSquareRight2()==1)
	{
		HDC hDc = GetDC(hWnd);
		SquareRight();
		g_nList++;
		OnPaint(hDc);
		ReleaseDC(hWnd, hDc);
	}
	
}

void SquareRight()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 9; j >= 0; j--)
		{
			if (g_arrBackGround[i][j] == 1)
			{
				g_arrBackGround[i][j + 1] = g_arrBackGround[i][j];
				g_arrBackGround[i][j] = 0;
			}
		}
	}
}

int CanSquareRight()
{
	for (int i = 0; i < 20; i++)
	{
		if (g_arrBackGround[i][9] == 1)
		{
			return 0;
		}
	}
	return 1;
}

int CanSquareRight2()
{
	for (int i = 0; i < 20; i++)
	{
		for (int j = 9; j >= 0; j--)
		{
			if (g_arrBackGround[i][j] == 1 && g_arrBackGround[i][j+1]==2)
			{
				return 0;
			}
		}
	}
	return 1;
}

void OnDown(HWND hWnd)
{
	OnTimer(hWnd);
}

void OnChangeSquare(HWND hWnd)
{
	HDC hDc = GetDC(hWnd);
	switch (g_nSquareID)
	{
	case 0:
	case 1:
	case 2:
	case 3:
	case 4:
		if (CanSquareChangeShape() == 1)
			ChangeSquare();
		else
			return;
		break;
	case 5:
		return;          // 正方形不變形
	case 6:
		if (CanLineSquareChange() == 1)
			ChangeLineSquare();

		
		break;
	}

	OnPaint(hDc);
	ReleaseDC(hWnd, hDc);
}

void ChangeSquare()
{
	char arrSquare[3][3] = { 0 };
	
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)          // 背景塊複製出來
		{
			arrSquare[i][j] = g_arrBackGround[g_nLine + i][g_nList + j];      
		}
	}

	int nTemp;
	for (int i = 0; i < 3; i++)
	{
		nTemp = 2;
		for (int j = 0; j < 3; j++)
		{
			g_arrBackGround[g_nLine + i][g_nList + j] = arrSquare[nTemp][i];
			nTemp--;
		}
	}
}

int CanSquareChangeShape()
{
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (g_arrBackGround[g_nLine + i][g_nList + j] == 2)
				return 0;
		}
	}

	if (g_nList < 0)
		g_nList = 0;
	else if (g_nList > 7)
		g_nList = 7;
	return 1;
}

void ChangeLineSquare()
{
	if (g_arrBackGround[g_nLine][g_nList - 1] == 1)
	{
		// 清零
		g_arrBackGround[g_nLine][g_nList - 1] = 0;
		g_arrBackGround[g_nLine][g_nList + 1] = 0;
		g_arrBackGround[g_nLine][g_nList + 2] = 0;

		if (g_arrBackGround[g_nLine + 1][g_nList] == 2)
		{
			g_arrBackGround[g_nLine - 3][g_nList] = 1;
			g_arrBackGround[g_nLine - 2][g_nList] = 1;
			g_arrBackGround[g_nLine - 1][g_nList] = 1;
			//g_nLine -= 2;
			
		}
		else if(g_arrBackGround[g_nLine + 2][g_nList] == 2)
		{
			g_arrBackGround[g_nLine + 1][g_nList] = 1;
			g_arrBackGround[g_nLine - 1][g_nList] = 1;
			g_arrBackGround[g_nLine - 2][g_nList] = 1;
			//g_nLine--;
		
		}
		else
		{
			// 元素賦值
			g_arrBackGround[g_nLine - 1][g_nList] = 1;
			g_arrBackGround[g_nLine + 1][g_nList] = 1;
			g_arrBackGround[g_nLine + 2][g_nList] = 1;
		}
		
	}
	else
	{
		// 清零
		g_arrBackGround[g_nLine - 1][g_nList] = 0;
		g_arrBackGround[g_nLine + 1][g_nList] = 0;
		g_arrBackGround[g_nLine + 2][g_nList] = 0;
		if (g_arrBackGround[g_nLine][g_nList + 1] == 2 || g_nList==9)
		{
			g_arrBackGround[g_nLine][g_nList - 1] = 1;
			g_arrBackGround[g_nLine][g_nList - 2] = 1;
			g_arrBackGround[g_nLine][g_nList - 3] = 1;
			g_nList -= 2;
		}
		else if (g_arrBackGround[g_nLine][g_nList + 2] == 2|| g_nList ==8)
		{
			g_arrBackGround[g_nLine][g_nList + 1] = 1;
			g_arrBackGround[g_nLine][g_nList - 1] = 1;
			g_arrBackGround[g_nLine][g_nList - 2] = 1;
			g_nList -= 2;
		}
		else if (g_arrBackGround[g_nLine][g_nList - 1] == 2 || g_nList == 0)
		{
			g_arrBackGround[g_nLine][g_nList + 1] = 1;
			g_arrBackGround[g_nLine][g_nList + 2] = 1;
			g_arrBackGround[g_nLine][g_nList + 3] = 1;
			g_nList++;
		}

		else
		{
			g_arrBackGround[g_nLine][g_nList - 1] = 1;
			g_arrBackGround[g_nLine][g_nList + 1] = 1;
			g_arrBackGround[g_nLine][g_nList + 2] = 1;
		}
	
		
	}
}

int CanLineSquareChange()
{
	int i, j;
	for (i = 1; i < 4; i++)
	{
		if (g_arrBackGround[g_nLine][g_nList + i] == 2
			|| g_nList+i>9)
		{
			break;
		}
	}
	for (j = 1; j < 4; j++)
	{
		if (g_arrBackGround[g_nLine][g_nList - j] == 2 || g_nList - j < 0)
		{
			break;
		}
	}

	if (i - 1 + j - 1 < 3)
		return 0;
	
	return 1;
	
}

void DestroyOneLineSquare()
{
	int nSum = 0;
	for (int i = 19; i >= 0; i--)
	{
		for (int j = 0; j < 10; j++)
		{
			nSum += g_arrBackGround[i][j];
		}
		if (nSum == 20)
		{
			g_nScore += 10;
			for (int k = i - 1; k >= 0; k--)
			{
				for (int l = 0; l < 10; l++)
				{
					g_arrBackGround[k + 1][l] = g_arrBackGround[k][l];
				}
			}
			i = 20;
		}
		nSum = 0;
	}

}

void ShowScore(HDC hMemDC)
{
	char strScore[10] = { 0 };                                     // 分數字符串
	Rectangle(hMemDC, 300, 0, 500, 600);
	sprintf_s(strScore, "%d", g_nScore, strlen(strScore));
	TextOut(hMemDC, 400, 100, strScore, strlen(strScore));
}

int CanGameOver()
{
	for (int i = 0; i < 10; i++)
	{
		if (g_arrBackGround[0][i] == 2)
		{
			MessageBox(NULL,"GameOver","提示",MB_OK);           // 遊戲結束
			return 0;
		}
	}
	return 1;
}