win32-c語言實現俄羅斯方塊

Renaway發表於2018-02-15


這是我跟著一個視訊教程做的。先看效果,後上程式碼,核心是二維陣列(矩陣)的遍歷和win32的一些基礎,有時間談談細節。







我使用的是vc++6.0,更高版本也可以,vc++6.0下載地址: http://download.csdn.net/download/richard1997/10252249

1.開啟vs,新建專案:右上角依次開啟File->選擇New...      或者直接Ctr+N;

2.輸入專案名字,比如我輸入Russia,你接下來可以選擇你的專案存放路徑;


 3.點選Win32 Application,然後單擊OK按鈕,也可以直接雙擊Win32 Application;


4.單選按鈕預設為An empty project,我們無須更改什麼,直接點選Finish;



5.彈出的New Project Information對話方塊直接選擇ok;

6.這是一個空專案,我們需要為其新增我們的c程式,類似第1步的方法Ctrl+N開啟建立檔案對話方塊;

7.填寫檔名字,比如main.c,然後點選選擇C++ Source File,點選ok,或者填完檔名後直接雙擊;



8.檔案建立好後,游標會在工作臺上閃爍(背景由灰變白),你就可以在上面編輯main.c檔案了。複製下面的程式碼到你的main.c檔案裡:

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

#define DEF_TIMER1 1234
// 背景陣列
char g_arrBackGround[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;

LRESULT CALLBACK PEluosi(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam);
void OnPaint(HDC hdc);
void CreateRandomSqare();
void OnCreate();
void CopySqareToBack();
void PaintSqare(HDC hMenDc);
void OnReturn();
void SqareDown();
void OnTimer(HWND hWnd);
int CanSqareDown(); 
void Change1To2();
void PaintSqare2(HDC hMenDc);
int CanSqareDown2();
void OnLeft(HWND hWnd);
void SqareLeft();
int CanSqareLeft();
int CanSqareLeft2();
void OnRight(HWND hWnd);
void SqareRight();
int CanSqareRight();
int CanSqareRight2();
void OnDown(HWND hWnd);
void OnChangeSqare(HWND hWnd);
void ChangeSqare();
int CanSqareChangeShape();
void ChangeLineSqare();
int CanLineSqareChange();
void DestroyOneLineSqare();
void ShowScore(HDC hMenDc);
int CanGameOver();

// 1.WINAPI:呼叫約定
//1號引數控制程式碼 一個整數, 視窗的唯一標識,2號引數 前一個 沒什麼用 , 3號引數 命令列引數 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPTSTR IpCmdLine, int nCmdShow)
{
	
	//初始化視窗類
	WNDCLASSEX wc;

	HWND hWnd;
	MSG msg;

	wc.cbClsExtra = 0;
	wc.cbSize = sizeof(WNDCLASSEXA);
	wc.cbWndExtra = 0;
	wc.hbrBackground = (HBRUSH)COLOR_3DLIGHT;
	wc.hCursor = LoadCursor(NULL, IDC_HELP); //游標
	wc.hIcon = LoadIcon(NULL, IDI_HAND); //圖示
	wc.hIconSm = NULL;  
	wc.hInstance = hInstance;
	wc.lpfnWndProc = PEluosi; //回撥函式地址
	wc.lpszClassName = "els"; //視窗類的名字,不重複,作業系統看
	wc.lpszMenuName = NULL;
	wc.style = CS_HREDRAW | CS_VREDRAW;

	 //註冊視窗物件
	if (RegisterClassEx(&wc) == 0)
	{
		int a = GetLastError(); //函式 		errno

		
		return 0;
	}

	//建立視窗
	hWnd =  CreateWindowEx(WS_EX_TOPMOST, "els", "RR\'s Block", WS_OVERLAPPEDWINDOW,100,40, 500, 641,NULL, NULL,hInstance, NULL);
	if (hWnd == NULL) //視窗控制程式碼 123 視窗唯一標識
	{
		return 0;
	}

	//顯示視窗
	ShowWindow(hWnd, SW_NORMAL); //返回值 0:隱藏 非零:顯示
	
	//訊息迴圈
	while (GetMessage(&msg, NULL, 0, 0))
	{
		//翻譯訊息
		TranslateMessage(&msg);
		//分發訊息
		DispatchMessage(&msg);
	}
	return 0;
}
//win32控制檯 主函式 int main()
//win32專案  主函式

LRESULT CALLBACK PEluosi(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT pt;
	HDC hdc;
	switch (nMsg)
	{
	
	case WM_CREATE:  //視窗建立初期只產生一次
	  OnCreate();
		break;
	case WM_TIMER:
		OnTimer(hWnd);
		break;
	case WM_PAINT:
	hdc = BeginPaint(hWnd, &pt);
		//畫視窗的內容
		OnPaint(hdc);

		EndPaint(hWnd, &pt);
		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:
			OnChangeSqare(hWnd);
			break;
		case VK_DOWN:
			OnDown(hWnd);
			break;
		}
		break;
	case WM_DESTROY:
		KillTimer(hWnd, DEF_TIMER1);
		PostQuitMessage(0);
		break;
	}
	return DefWindowProc(hWnd, nMsg, wParam, lParam); //功能:
}



void OnCreate()
{
		srand((unsigned int)time(NULL));
	    CreateRandomSqare();
		CopySqareToBack();
}

void CreateRandomSqare()
{

	int nIndex = rand() % 7;
	switch(nIndex)
	{
	case 0:
		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 1:
		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 2:
		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 3:
		g_arrSqare[0][0] = 0, g_arrSqare[0][1] = 0, g_arrSqare[0][2] = 1, 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 4:
		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;
	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;
		g_nLine = 0;
		g_nList = 4;
		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;
     }
	g_nSqareID = nIndex;
	 
}
void CopySqareToBack()
{
	int i, j;
	for (i = 0; i < 2; i++)
		for (j = 0; j < 4; j++)
			g_arrBackGround[i][j + 3] = g_arrSqare[i][j];
}
void PaintSqare(HDC hMenDc)
{
	HBRUSH hOldBrush;
	HBRUSH hNewBrush;
	
	 int i , j;
	 Rectangle(hMenDc, 0, 0, 300 ,600);


	 hNewBrush = CreateSolidBrush(RGB(245, 253, 98));
     hOldBrush = SelectObject(hMenDc, hNewBrush);

	 for (i = 0; i < 20; i++)
	 {
		 for (j = 0; j < 10; j++)
			 if (g_arrBackGround[i][j] == 1)
			 Rectangle(hMenDc, j * 30, i * 30, j * 30 + 30 , i * 30 + 30);
	 }
	
	hNewBrush = SelectObject(hMenDc, hOldBrush);
	DeleteObject(hNewBrush);
}

void PaintSqare2(HDC hMenDc)
{
	int i , j;
	HBRUSH hOldBrush;
	HBRUSH hNewBrush = CreateSolidBrush(RGB(130, 64, 238));
	hOldBrush = SelectObject(hMenDc, hNewBrush);

	for (i = 0; i < 20; i++)
	 {
		 for (j = 0; j < 10; j++)
			 if (g_arrBackGround[i][j] == 2)
			 Rectangle(hMenDc, j * 30, i * 30, j * 30 + 30 , i * 30 + 30);
	 }

	hNewBrush = SelectObject(hMenDc, hOldBrush);
	DeleteObject(hNewBrush);
}
void OnPaint(HDC hdc)
{
     
		//建立相容性DC
		HDC hMenDc = CreateCompatibleDC(hdc);
		//建立一張紙
		HBITMAP hBitmapBack = CreateCompatibleBitmap(hdc, 500, 600);
		//關聯起來
		SelectObject(hMenDc, hBitmapBack);

		PaintSqare(hMenDc);
		PaintSqare2(hMenDc);

		//傳遞
		ShowScore(hMenDc);
		BitBlt(hdc, 0, 0, 500, 600, hMenDc, 0, 0, SRCCOPY);
		DeleteObject(hBitmapBack);
		DeleteDC(hMenDc);
}

void OnReturn(HWND hWnd)
{
	//開啟定時器
	SetTimer(hWnd, DEF_TIMER1, 500, NULL);
}

//方塊下落
void SqareDown()
{
	int i, j;
	for (i = 19; i >= 0; i--)
	{
		for (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 (CanSqareDown() && CanSqareDown2())
	{
	SqareDown();
	g_nLine++;
	}
	else
	{
		// 1 to 2
		Change1To2();
		DestroyOneLineSqare();
		//遊戲結束
		if (!CanGameOver())
		{
			KillTimer(hWnd, DEF_TIMER1);
			return ;

		}
		//產生隨機塊
		CreateRandomSqare();
		CopySqareToBack();
	}
	//顯示方塊

	OnPaint(hDc);

	ReleaseDC(hWnd, hDc);  //人工釋放
}

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

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

int CanSqareDown2()
{
	int i, j;

	for (i = 19; i >= 0; i--)
	{
		for (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)
{
	HDC hDc = GetDC(hWnd);

	if (CanSqareLeft() && CanSqareLeft2())
	{
	// 方塊左移
	SqareLeft();
	g_nList--;
	//顯示方塊
	OnPaint(hDc);
	ReleaseDC(hWnd, hDc);
	}

	
	

}

void SqareLeft()
{
	int i, j;

	for (i = 0; i < 20; i++)
	{
		for (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 CanSqareLeft()
{
	int i;
	for (i = 0; i < 20; i++)
	{
		if (g_arrBackGround[i][0] == 1)
		{
			return 0;
		}
	}
	return 1;
}

int CanSqareLeft2()
{
	int i, j;
	for (i = 0; i < 20; i++)
	{
		for (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 (CanSqareRight() && CanSqareRight2())
	{
	HDC hDc = GetDC(hWnd);
	// 方塊右移
	g_nList++;
	SqareRight();
	OnPaint(hDc);
	ReleaseDC(hWnd, hDc);
	}

}

void SqareRight()
{
	int i, j;
	for (i = 0; i < 20; i++)
	{
		for (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 CanSqareRight()
{
   int i;
   for (i = 0; i < 20; i++)
   {
	   if (g_arrBackGround[i][9] == 1)
		   return 0;
   }
   return 1;
}

int CanSqareRight2()
{
	int i,j;
	for (i = 0; i < 20; i++)
	{
		for (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 OnChangeSqare(HWND hWnd)
{
	HDC hDc = GetDC(hWnd);
      switch (g_nSqareID)
	  {
	  case 0:
	  case 1:
	  case 2:
	  case 3:
	  case 4:
		  if (CanSqareChangeShape())
		  {
		  ChangeSqare();
		  }
		  else
		  {
			  return;
		  }
		  break;
	  case 5:
		  return ;
	  case 6:
		  if (CanLineSqareChange())
		  {
	        ChangeLineSqare();
		  }
		  break;
	  
	  }

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

void ChangeSqare()
{
	char arrSqare[3][3] = {0};
	int i, j;
	int nTemp = 2;

	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			arrSqare[i][j] = g_arrBackGround[g_nLine + i][g_nList + j];
		}
	
	}

	//變形後複製回去
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
		 g_arrBackGround[g_nLine + i][g_nList + j] = arrSqare[nTemp--][i];
		}
			nTemp = 2; 
	}

}

int CanSqareChangeShape()
{
	int i, j;

	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
		{
			if (g_arrBackGround[g_nLine + i][g_nList + j] == 2)
				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 (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 - 1][g_nList] = 1;
			g_arrBackGround[g_nLine - 2][g_nList] = 1;
			g_arrBackGround[g_nLine - 3][g_nList] = 1;
		}
		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;
		}
		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 || 9 == g_nList)
		{
			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 = g_nList - 2;

		}
		else if (g_arrBackGround[g_nLine][g_nList + 2] == 2 || 8 == g_nList)
		{
			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 = g_nList - 1;
		}
		else if (g_arrBackGround[g_nLine][g_nList - 1] == 2 || !g_nList)
		{
			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 = g_nList + 1;
		}
		
		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 CanLineSqareChange()
{
	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 + j < 5)
		return 0;

	return 1;
}

void DestroyOneLineSqare()
{
	int i, j, n;
	int nSum = 0;

	for (i = 19; i >= 0; i--)
	{
		for (j = 0; j < 10; j++)
		{
			nSum += g_arrBackGround[i][j];
		}

		if (nSum == 20)
		{
			for(n = i - 1; n >= 0; n--)
			{
				for (j = 0; j < 10; j++)
				{
					g_arrBackGround[n + 1][j] = g_arrBackGround[n][j];
				}
			}
			g_nScore++;
			// 消除兩行的bug
			i = 20;
		}
		nSum = 0;
	}

}

void ShowScore(HDC hMenDc)
{
		char strScore[10] = {0};
		
		Rectangle(hMenDc, 300, 0, 500, 600);

        itoa(g_nScore, strScore, 10);
	
		TextOut(hMenDc, 356, 140, "分數:", strlen("分數:"));
		TextOut(hMenDc, 390, 140, strScore, strlen(strScore));
}

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

9,複製好後,摁F7,觀測下面的編譯輸出資訊:如果是0 error(s), 0 warning (s)。那麼只需摁Ctrl+F5就可以看到我們剛開始看到的效果了。如果還是有問題,那麼要麼是環境的問題(中文亂碼),要麼是你執行步驟的問題。



未完待續...

相關文章