Win32俄羅斯方塊

yusenDong發表於2017-03-08

elsHead.h

#pragma once

#ifndef DEF_ELS_HEAD
#define DEF_ELS_HEAD
#define DEF_TIMER1 1234
#define WIDTH 700       
#define HEIGHT 655

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

void onPaint(HDC hdc);
void onCreat();
// 顯示方塊
void paintSqare(HDC hdc);
// 產生隨機塊
int createRandSqare();
// 隨機塊貼近背景
void copySqareToBack();

// 按鍵
void onReturn(HWND hwnd);
void onTimer(HWND hwnd);
void onUp(HWND hwnd);
void onLeft(HWND hwnd);
void onRight(HWND hwnd);

// 方塊移動
void sqareDown();
void sqareLeft();
void sqareRight();

// 方塊停在最底下
int canSqareDown();
// 把1變成2
void change();
// 方塊停止下落
int sqareStop();
// 方塊左右移動
int canSqareRight();
int canSqareLeft();
// 方塊停止左右移動
int sqareLeftStop();
int sqareRightStop();

// 消除完整行
void destroyOneLine();
// 方塊變形
void sqareChange();

#endif

elsHead.cpp

#include "elsHead.h"
// 背景陣列
char g_arrBackGround[20][16] = { 0 };
char g_arrSqare[2][4] = { 0 };
char g_;
int g_row = 0;
int g_list = 0;
int g_sqareID;

void onPaint(HDC hdc) {
    // 相容性DC
    HDC comdc = CreateCompatibleDC(hdc);
    // 建立一張紙
    HBITMAP hBitmap = CreateCompatibleBitmap(hdc, WIDTH, HEIGHT);
    // 關聯起來
    SelectObject(comdc, hBitmap);
    paintSqare(comdc);
    // 傳遞
    BitBlt(hdc, // 目標DC
        5,      // 起始x
        5,      // 起始y
        480,  // 目標區域x
        600,  // 目標區域y
        comdc,  // 源DC
        0, 0, SRCCOPY);

    // 釋放DC
    DeleteObject(hBitmap);
    DeleteDC(comdc);
}

void onCreat()
{
    srand((unsigned int)time(NULL));
    createRandSqare();
    copySqareToBack();
}
// 顯示方塊
void paintSqare(HDC comdc)
{
    int i = 0;
    int j = 0;
    // 遍歷
    for (i = 0;i < 20;i++) 
    {
        for (j = 0;j < 16;j++)
        {
            // 如果是1或2 畫出方塊
            if(g_arrBackGround[i][j] == 1 || g_arrBackGround[i][j] == 2)
                Rectangle(comdc, 30 * j , 30 * i, 30 + 30 * j, 30 + 30 * i);
        }
    }
}
// 產生隨機塊
int createRandSqare()
{
    int n;
    n = rand() % 7 + 1;
    g_sqareID = n;
    // 方塊型別
    switch (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] = 1;g_arrSqare[1][1] = 1;g_arrSqare[1][2] = 0;g_arrSqare[1][3] = 0;
        break;

        // 一條的
    case 2: 
        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_row = 0;
        g_list = 6;
        break;

        // 上面兩個下面兩個,上邊靠左
    case 3:
        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_row = 0;
        g_list = 6;
        break;

        // 上面倒著的
    case 4:
        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_row = 0;
        g_list = 6;
        break;

        // 七型,右邊高
    case 5:
        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_row = 0;
        g_list = 6;
        break;

        // 七型,左邊高
    case 6:
        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_row = 0;
        g_list = 6;
        break;

        // 山形
    case 7:
        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_row = 0;
        g_list = 6;
        break;

    }
    return 0;
}
// 隨機塊貼近背景
void copySqareToBack()
{
    int i, j;
    i = 0;
    j = 0;
    for ( i = 0; i < 2; i++)
    {
        for (j = 0; j < 4; j++)
        {
            g_arrBackGround[i][j + 6] = g_arrSqare[i][j];
        }
    }
}

// 按鍵訊息
void onReturn(HWND hwnd)
{
    // 開啟定時器
    SetTimer(hwnd, DEF_TIMER1, 1000, NULL);
}
void onRight(HWND hwnd)
{
    // 滿足條件右移
    if (canSqareRight() == 1 && sqareRightStop() == 1 )
    {
        // 獲取當前視窗的控制程式碼,記得釋放
        HDC hdc = GetDC(hwnd);
        sqareRight();
        g_list++;
        // 顯示方塊,並且相容性DC
        onPaint(hdc);
        // 釋放
        ReleaseDC(hwnd, hdc);
    }
}
void onLeft(HWND hwnd)
{
    // 滿足條件左移
    if (canSqareLeft() == 1 && sqareLeftStop() == 1)
    {
        // 獲取當前視窗的控制程式碼,記得釋放
        HDC hdc = GetDC(hwnd);
        sqareLeft();
        g_list--;
        // 顯示方塊,並且相容性DC
        onPaint(hdc);
        // 釋放
        ReleaseDC(hwnd, hdc);
    }
}
void onDown(HWND hwnd)
{
    onTimer(hwnd);
}
void onUp(HWND hwnd)
{
    HDC hdc = GetDC(hwnd);

    if (g_sqareID >= 2 && g_sqareID <= 7)
    {
        sqareChange();
    }

    onPaint(hdc);
    ReleaseDC(hwnd, hdc);
}

// 定時器響應函式
void onTimer(HWND hwnd)
{
    // 獲取當前視窗的控制程式碼,記得釋放
    HDC hdc = GetDC(hwnd);

    if (canSqareDown() == 1 && sqareStop() == 1)
    {
        sqareDown();
        g_row++;
    }

    else
    {
        // 把底層的 1 變成 2,這樣可以繼續判斷
        change();
        // 消除
        destroyOneLine();
        // 新的產生隨機塊
        createRandSqare();
        // 複製到新的背景上
        copySqareToBack();
    }
    // 顯示方塊,並且相容性DC
    onPaint(hdc);
    // 釋放
    ReleaseDC(hwnd, hdc);
}

// 方塊移動
void sqareDown()
{
    int i, j;
    for (i = 19;i >= 0;i--)
    {
        for (j = 0;j < 16;j++)
        {
            if (g_arrBackGround[i][j] == 1)
            {
                g_arrBackGround[i + 1][j] = 1;
                g_arrBackGround[i][j] = 0;
            }
        }
    }
}
void sqareLeft()
{
    int i, j;
    for (i = 0;i < 20;i++)
    {
        for (j = 0;j < 16;j++)
        {
            if (g_arrBackGround[i][j] == 1)
            {
                g_arrBackGround[i][j-1] = 1;
                g_arrBackGround[i][j] = 0;
            }
        }
    }
}
void sqareRight()
{
    int i, j;
    for (i = 0;i < 20;i++)
    {
        for (j = 15;j >= 0;j--)
        {
            if (g_arrBackGround[i][j] == 1)
            {
                g_arrBackGround[i][j + 1] = 1;
                g_arrBackGround[i][j] = 0;
            }
        }
    }
}

// 方塊是否到邊界停住
int canSqareDown()
{
    int i;
    for (i = 0;i < 16;i++)
    {
        if (g_arrBackGround[19][i] == 1)
        {
            return 0;
        }
    }
    return 1;
}
int canSqareLeft()
{
    int i;
    for (i = 0;i < 20;i++)
    {
        if (g_arrBackGround[i][0] == 1)
            return 0;
    }
    return 1;
}
int canSqareRight()
{
    int i;
    for (i = 0;i < 20;i++)
    {
        if (g_arrBackGround[i][15] == 1)
            return 0;
    }
    return 1;
}

// 把1變成2
void change()
{
    int i, j;
    for (i = 0;i < 20;i++)
    {
        for (j = 0;j < 16;j++)
        {
            if (g_arrBackGround[i][j] == 1)
            {
                g_arrBackGround[i][j] = 2;
            }
        }
    }
}

// 方塊遇到新方塊停止下落
int sqareStop()
{
    int i, j;
    for (i = 19;i >= 0;i--)
    {
        for (j = 0;j < 16;j++)
        {
            if (g_arrBackGround[i][j] == 1)
            {
                if (g_arrBackGround[i + 1][j] == 2)
                {
                    return 0;
                }
            }
        }
    }
    return 1;
}
int sqareLeftStop()
{
    int i, j;
    for (i = 19;i >= 0;i--)
    {
        for (j = 0;j < 16;j++)
        {
            if (g_arrBackGround[i][j] == 1)
            {
                if (g_arrBackGround[i][j - 1] == 2)
                {
                    return 0;
                }
            }
        }
    }
    return 1;
}
int sqareRightStop()
{
    int i, j;
    for (i = 0;i < 20;i++)
    {
        for (j = 15;j >= 0;j--)
        {
            if (g_arrBackGround[i][j] == 1)
            {
                if (g_arrBackGround[i][j + 1] == 2)
                {
                    return 0;
                }
            }
        }
    }
    return 1;
}

// 消除一行
void destroyOneLine()
{
    int i,j;
    int sum = 0;
    int temp = 0;

    for (i = 19;i >= 0;i--)
    {
        for (j = 0;j < 16;j++)
        {
            sum += g_arrBackGround[i][j];
        }
        if (sum == 32)
        {
            for (temp = i - 1;temp>=0;temp--)
                for (j = 0;j < 16;j++)
                {
                    g_arrBackGround[temp + 1][j] = g_arrBackGround[temp][j];
                }
        }
        sum = 0;
    }

}

void sqareChange()
{
    int i, j;
    char nArrSqare[3][3] = { 0 };
    // 把方塊複製出來
    for (i = 0;i < 3;i++)
    {
        for (j = 0;j < 3;j++)
        {
            nArrSqare[i][j] = g_arrBackGround[g_row + i][g_list + j];
        }
    }
    // 變形後複製回去
    for (i = 0;i < 3;i++)
    {
        for (j = 0;j < 3;j++)
        {
            g_arrBackGround[g_row + i][g_list + j] = nArrSqare[2-j][i];
        }
    }

}

main.c


#include "elsHead.h"

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
void onPaint(HDC hdc);

/*  主程式*/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

    WNDCLASSEX wc; /* A properties struct of our window */
    HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
    MSG msg; /* A temporary location for all messages */

             /* zero out the struct and set the stuff we want to modify */
    memset(&wc, 0, sizeof(wc));
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = WndProc; /* This is where we will send messages to */
    wc.hInstance = hInstance;
    wc.hCursor = LoadCursor(NULL, IDC_HAND);  //系統游標
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
    wc.lpszClassName = "WindowClass";
    wc.hIcon = LoadIcon(NULL, IDI_INFORMATION); /* Load a standard icon */
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); /* use the name "A" to use the project icon */

    if (!RegisterClassEx(&wc)) {
        MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "WindowClass", "Tetris", WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        60, /* x */
        60, /* y */
        WIDTH, /* width */
        HEIGHT, /* height */
        NULL, NULL, hInstance, NULL);

    if (hwnd == NULL) {
        MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    /*
    This is the heart of our program where all input is processed and
    sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
    this loop will not produce unreasonably high CPU usage */
    while (GetMessage(&msg, NULL, 0, 0) > 0) { /* If no error is received...*/
        TranslateMessage(&msg); /* Translate key codes to chars if present */
        DispatchMessage(&msg); /* Send it to WndProc */
    }
    return msg.wParam;
}

/* 回撥函式 */
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    switch (Message) {
        PAINTSTRUCT p;
        HDC hdc;
    // 視窗建立初期只產生一次,一般做資料初始化的工作 
    case WM_CREATE:
        //GetLastError();
        onCreat();
        break;
    // 視窗產生變化,必須更新時,由這個訊息通知程式 
    case WM_PAINT:
        /* getDC,視窗可操作區域的標識 */
        hdc = BeginPaint(hwnd, &p);
        onPaint(hdc);
        /* 關閉DC */
        EndPaint(hwnd, &p);
        //GetLastError();
        break;
    // 鍵盤資訊
    case WM_KEYDOWN:
        switch (wParam)
        {
        case VK_RETURN:
            onReturn(hwnd);
            break;
        case VK_RIGHT:
            onRight(hwnd);
            break;
        case VK_LEFT:
            onLeft(hwnd);
            break;

        case VK_UP:
            onUp(hwnd);
            break;
        case VK_DOWN:
            onDown(hwnd);
            break;
        }
        // 定時器訊息
    case WM_TIMER:
        onTimer(hwnd);
        break;

    case WM_DESTROY: {
        PostQuitMessage(0);
        break;
    }

    /* All other messages (a lot of them) are processed using default procedures */
    default:
        return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    return 0;
}

相關文章