1. 程式人生 > >GDI打磚塊遊戲

GDI打磚塊遊戲

菜單 ips 窗口 nbsp ide cpp instance 碰撞 style

//header.h文件

#pragma once
#include <windows.h>
#include <stdio.h>

#define KEYDOWN(vk_code)((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEYUP(vk_code)    ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

//Game.h文件

#pragma once
#include "header.h"

const int    BRICKNUM = 20;
typedef 
struct { int x; //球的位置 int y; int radius; //球的半徑 int speed; //球的速度 int moveX; //每次移動的值(帶正負) int moveY; //每次移動的值 COLORREF color; //球的顏色 }BALL; typedef struct { int width; //
磚的寬度 int height; //磚的高度 RECT rect; COLORREF color; //磚的顏色 bool exist; }BRICK; class CGame { private: HWND m_hWnd; HDC m_hdc; RECT m_wndRect; BALL m_Ball; BRICK* m_pBrick; BRICK m_Bar;
public: CGame(HWND hWnd); ~CGame(void); void Render(); void ClearScreen(); //清除屏幕 void DrawBrick(); //畫磚塊 void DrawBar(); //畫擋板 void DrawBall(); //畫小球 void MoveBall(); //小球移動 void TestBrickCollide(); //判斷碰撞磚塊 void TestBarCollide(); //判斷碰撞擋板 void MoveBar(int speed); //移動擋板 };

//Game.cpp文件

#include "Game.h"
//---------------------------------------------------------
// Name: CGame
// Desc: 構造函數,初始化
//---------------------------------------------------------
CGame::CGame(HWND  hWnd)
{
    m_hWnd    = hWnd;
    m_hdc    = GetDC(m_hWnd);
    GetWindowRect(m_hWnd, &m_wndRect);

    //初始化磚塊
    m_pBrick    = new BRICK[BRICKNUM];
    int StartX    = m_wndRect.right / 5;    //第一塊磚塊的位置
    int StartY    = m_wndRect.bottom / 6;
    for(int i = 0; i < BRICKNUM; i++)
    {
        (m_pBrick + i)->width = 50;
        (m_pBrick + i)->height = 25;
        (m_pBrick + i)->color = RGB(255, 40, 100);
        (m_pBrick + i)->rect.left = StartX +(i % 5) *(m_pBrick + i)->width;
        (m_pBrick + i)->rect.top = StartY +(i / 5) *(m_pBrick + i)->height;
        (m_pBrick + i)->rect.right =(m_pBrick + i)->rect.left +(m_pBrick + i)->width;
        (m_pBrick + i)->rect.bottom    =(m_pBrick + i)->rect.top +(m_pBrick + i)->height;
        (m_pBrick + i)->exist = true;
    }

    //初始化擋板
    m_Bar.color = RGB(0, 0, 255);
    m_Bar.exist = true;
    m_Bar.height = 15;
    m_Bar.width = 60;
    m_Bar.rect.left = m_wndRect.right / 2 - m_Bar.width / 2;    //遊戲開始畫在//窗口中央底部
    m_Bar.rect.top = m_wndRect.bottom *(8.0 / 10);
    m_Bar.rect.right = m_Bar.rect.left + m_Bar.width;
    m_Bar.rect.bottom = m_Bar.rect.top  + m_Bar.height;

    //初始化小球
    m_Ball.color = RGB(0, 255, 255);
    m_Ball.radius = 10;
    m_Ball.x = m_Bar.rect.left + m_Bar.width / 2;    //小球開始出現在擋板的正上方//中央

    m_Ball.y = m_Bar.rect.top  - m_Ball.radius;
    m_Ball.speed = 1;
    m_Ball.moveX = m_Ball.speed;
    m_Ball.moveY = -m_Ball.speed;

}
//---------------------------------------------------------
// Name: ~CGame
// Desc: 析構函數
//---------------------------------------------------------
CGame::~CGame(void)
{
    ReleaseDC(m_hWnd, m_hdc);
}

//---------------------------------------------------------
// Name: Render
// Desc: 遊戲的渲染部分
//---------------------------------------------------------
void CGame::Render()
{
    ClearScreen();
    DrawBrick();
    MoveBar(3);
    DrawBar();
    TestBrickCollide();
    TestBarCollide();
    MoveBall();
    DrawBall();
}

//---------------------------------------------------------
// Name: DrawBrick
// Desc: 畫出沒被小球打中的磚塊
//---------------------------------------------------------
void CGame::DrawBrick()
{
    bool gamesuccess = true;
    for(int i = 0; i < BRICKNUM; i++)
    {
        if((m_pBrick + i)->exist)
        {
            //畫實心矩形
            HBRUSH    hBrush    = ::CreateSolidBrush((m_pBrick + i)->color);
            SelectObject(m_hdc, hBrush);
            ::FillRect(m_hdc, &(m_pBrick + i)->rect, hBrush);
            SelectObject(m_hdc, hBrush);
            DeleteObject(hBrush);

            //畫矩形外框
            HPEN hPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
            SelectObject(m_hdc, hPen);
            MoveToEx(m_hdc,(m_pBrick + i)->rect.left, (m_pBrick + i)->rect.top, NULL);
            LineTo(m_hdc, (m_pBrick + i)->rect.right, (m_pBrick + i)->rect.top);
            LineTo(m_hdc, (m_pBrick + i)->rect.right, (m_pBrick + i)->
rect.bottom);
            LineTo(m_hdc, (m_pBrick + i)->rect.left, (m_pBrick + i)->
rect.bottom);
            LineTo(m_hdc, (m_pBrick + i)->rect.left, (m_pBrick + i)->rect.top);
            SelectObject(m_hdc, hPen);
            DeleteObject(hPen);

            gamesuccess = false;
        }
    }
    
    if(gamesuccess)
    {
        MessageBox(m_hWnd, L"遊戲成功!", L"Congratulation!", MB_OK);
        exit(0);
    }
}

//---------------------------------------------------------
// Name: DrawBar
// Desc: 畫擋板
//---------------------------------------------------------
void CGame::DrawBar()
{
    HBRUSH hBrush = CreateSolidBrush(m_Bar.color);
    SelectObject(m_hdc, hBrush);
    FillRect(m_hdc, &m_Bar.rect, hBrush);
    SelectObject(m_hdc, hBrush);
    DeleteObject(hBrush);

    HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0));
    SelectObject(m_hdc, hPen);
    MoveToEx(m_hdc, m_Bar.rect.left, m_Bar.rect.top, NULL);
    LineTo(m_hdc, m_Bar.rect.right, m_Bar.rect.top);
    LineTo(m_hdc, m_Bar.rect.right, m_Bar.rect.bottom);
    LineTo(m_hdc, m_Bar.rect.left, m_Bar.rect.bottom);
    LineTo(m_hdc, m_Bar.rect.left, m_Bar.rect.top);
    SelectObject(m_hdc, hPen);
    DeleteObject(hPen);
}

//---------------------------------------------------------
// Name: DrawBall
// Desc: 畫小球
//---------------------------------------------------------
void CGame::DrawBall()
{
    HBRUSH hBrush = CreateSolidBrush(m_Ball.color);
    HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 255));
    SelectObject(m_hdc, hBrush);
    SelectObject(m_hdc, hPen);
    Ellipse(m_hdc, m_Ball.x - m_Ball.radius, m_Ball.y - m_Ball.radius, m_Ball.x + m_Ball.radius, m_Ball.y + m_Ball.radius);
    SelectObject(m_hdc, hPen);
    SelectObject(m_hdc, hBrush);
    DeleteObject(hPen);
    DeleteObject(hBrush);
}

//---------------------------------------------------------
// Name: ClearScreen
// Desc: 清屏
//---------------------------------------------------------
void CGame::ClearScreen()
{
    HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));
    SelectObject(m_hdc, hBrush);
    FillRect(m_hdc, &m_wndRect, hBrush);
    SelectObject(m_hdc, hBrush);
    DeleteObject(hBrush);
}

//---------------------------------------------------------
// Name: MoveBall
// Desc: 移動小球
//---------------------------------------------------------
void CGame::MoveBall()
{
    if(m_Ball.x + m_Ball.moveX + m_Ball.radius > m_wndRect.right ||
        m_Ball.x + m_Ball.moveX - m_Ball.radius < m_wndRect.left)
    {
        m_Ball.moveX = -m_Ball.moveX;
    }
    if(m_Ball.y + m_Ball.moveY - m_Ball.radius < m_wndRect.top)
    {
        m_Ball.moveY = -m_Ball.moveY;
    }
    if(m_Ball.y + m_Ball.moveY + m_Ball.radius > m_wndRect.bottom)
    {
        MessageBox(m_hWnd, L"遊戲結束!", L"GameOver", MB_OK);
        exit(0);
    }
    m_Ball.x += m_Ball.moveX;
    m_Ball.y += m_Ball.moveY;
}

//---------------------------------------------------------
// Name: TestBrickCollide
// Desc: 測試小球是否與磚塊碰撞
//---------------------------------------------------------
void CGame::TestBrickCollide()
{
    POINT    pt;
    pt.x = m_Ball.x;
    pt.y = m_Ball.y;
    HRGN hrgn = ::CreateRectRgn(m_Ball.x - m_Ball.radius, m_Ball.y - 
m_Ball.radius, m_Ball.x + m_Ball.radius, m_Ball.y + m_Ball.radius);
    for(int i = 0; i < BRICKNUM; i++)
    {
        
        if((m_pBrick + i)->exist &&
            RectInRegion(hrgn, &(m_pBrick + i)->rect))
        {
            if(m_Ball.x <(m_pBrick + i)->rect.left &&
                m_Ball.moveX > 0)
            {
                (m_pBrick + i)->exist = false;
                m_Ball.moveX = -m_Ball.moveX;
                return;
            }
            if(m_Ball.x >(m_pBrick + i)->rect.right &&
                m_Ball.moveX < 0)
            {
                (m_pBrick + i)->exist = false;
                m_Ball.moveX = -m_Ball.moveX;
                return;
            }
            if(m_Ball.y <(m_pBrick + i)->rect.top &&
                m_Ball.moveY > 0)
            {
                (m_pBrick + i)->exist = false;
                m_Ball.moveY = -m_Ball.moveY;
                return;
            }
            if(m_Ball.y >(m_pBrick + i)->rect.bottom &&
                m_Ball.moveY < 0)
            {
                (m_pBrick + i)->exist = false;
                m_Ball.moveY = -m_Ball.moveY;
                return;
            }
        }
    }
    DeleteObject(hrgn);
}
//---------------------------------------------------------
// Name: TestBarCollide
// Desc: 測試小球是否與擋板碰撞
//---------------------------------------------------------
void CGame::TestBarCollide()
{
    HRGN hrgn = ::CreateRectRgn(m_Ball.x - m_Ball.radius, m_Ball.y - 
m_Ball.radius, m_Ball.x + m_Ball.radius, m_Ball.y + m_Ball.radius);
    if(RectInRegion(hrgn, &m_Bar.rect))
    {
        m_Ball.moveY = -m_Ball.moveY;
        float a =(m_Ball.x - m_Bar.rect.left);
        float b = a / m_Bar.width;
        m_Ball.moveX =((b - 0.5) * 5);
    }
    DeleteObject(hrgn);
}

//---------------------------------------------------------
// Name: MoveBar
// Desc: 移動擋板
//---------------------------------------------------------
void CGame::MoveBar(int speed)
{
    if(KEYDOWN(VK_LEFT))
    {
        if(m_Bar.rect.left - speed < m_wndRect.left)
            return;
        m_Bar.rect.left  -= speed;
        m_Bar.rect.right -= speed;
    }
    if(KEYDOWN(VK_RIGHT))
    {
        if(m_Bar.rect.right + speed > m_wndRect.right)
            return;
        m_Bar.rect.left  += speed;
        m_Bar.rect.right += speed;
    }
}

//main.cpp文件

#include "header.h"
#include "Game.h"

CGame* g_pGame;
//windows 的回調函數
long FAR PASCAL WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM    lParam)
{
    switch(message)
    {
    case WM_DESTROY:
        PostQuitMessage(0);    //向操作系統傳遞退出的消息,只有當窗口銷毀之後,WM_QUIT才能生效結束這個進程
    return 0;

    case WM_KEYDOWN:
        switch(wParam)
        {
            case VK_ESCAPE:
            PostMessage(hWnd, WM_CLOSE, 0, 0);    //向操作系統傳遞關閉窗口消息,WM_CLOSE會觸發WM_DESTROY消息
            break;
        }
        break;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);
}

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)    //縮放,如按最小化時,都由這個控制
{
    MSG msg;    //定義一個消息的對象
    HWND hWnd;    //窗口句柄
    WNDCLASS wc;        //定義窗口類

    //創建窗口類
    wc.style = CS_HREDRAW | CS_VREDRAW;    //支持水平和垂直重繪
    wc.lpfnWndProc = WindowProc;        //相應的消息處理函數
    wc.cbClsExtra = 0;                //附加內存空間
    wc.cbWndExtra = 0;                //附加內存空間
    wc.hInstance = hInstance;            //窗口的實例句柄
    wc.hIcon = NULL;                    //窗口的小圖標
    wc.hCursor = NULL;                            //窗口的鼠標形狀
    wc.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);//背景顏色
    wc.lpszMenuName = NULL;                        //窗口菜單
    wc.lpszClassName = L"createwindows";            //窗口名稱

    RegisterClass(&wc);    //註冊窗口句柄
    
    hWnd = CreateWindowEx(WS_EX_TOPMOST, L"createwindows", L"Create Window Title", WS_OVERLAPPEDWINDOW, 0,    0, 400, 300, NULL, NULL, hInstance,     NULL);            
    
    if(!hWnd)        //判斷窗口是否建立成功
    {
        MessageBox(NULL, L"窗口建立失敗!", L"error", NULL);
        return FALSE;
    }

    g_pGame = new CGame(hWnd);

    ShowWindow(hWnd, nCmdShow);        //顯示窗口
    UpdateWindow(hWnd);                //更新窗口,默認調用了回調函數
    
    while(true)
    {
        //接受系統消息(&msg 為 MSG 類型的信息結構體,NULL 窗口句柄,0, 0 表示
        //接受所有的窗口信息)
        if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
        {
            if(msg.message == WM_QUIT)
                break;
            TranslateMessage(&msg);        //轉化信息
            DispatchMessage(&msg);        //分配信息到相應的消息處理
        }
        else
        {
            g_pGame->Render();
            Sleep(10);
        }
    }
    return 1;
}

GDI打磚塊遊戲