WIN32 俄羅斯方塊
阿新 • • 發佈:2018-11-25
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; }