Win32实现简单游戏引擎

通过win32实现了简单的游戏引擎,通过模拟游戏引擎的加载、图形渲染以及游戏退出的操作来理解游戏引擎的基本原理。
文中分别使用了GDI以及Direct3D来实现,希望对你有所帮助。

// MyEngine.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include <stdio.h>
#include "MyEngine.h"
#include <time.h>
#include <d3d9.h>
#pragma comment(lib,"D3d9.lib")

#define MAX_LOADSTRING 100

// 全局变量: 
HINSTANCE hInst;                                // 当前实例
WCHAR szTitle[] = L"游戏引擎 - FPS:0";               // 标题栏文本
WCHAR szWindowClass[] = L"MyGameEngine";         // 主窗口类名
HWND  g_hMainWnd;

TCHAR g_Key[256] = { 0 };       // 按键检测
DWORD nWidth = 0;               // 保存当前窗口的宽
DWORD nHeight = 0;              // 保存当前窗口的高

LPDIRECT3D9 g_pD3D = NULL;
LPDIRECT3DDEVICE9 g_pDev = NULL;
LPDIRECT3DSURFACE9 g_pBackBuffer = NULL;
LPDIRECT3DSURFACE9 g_pSurface = NULL;

#define KEYDOWN(x) g_Key[x] 

DWORD GetRand(DWORD dwBase);    // 获取随机数

// 使用GDI绘图测试
DWORD OnGameInit_GDI();         // 模拟游戏引擎的加载
DWORD OnGameRender_GDI();       // 模拟游戏进行画面的渲染
DWORD OnGameOver_GDI();         // 模拟游戏退出时的清理工作

// 使用Direct3D测试
bool OnGameInit_D3D();          // 模拟游戏引擎的加载
bool OnGameRender_D3D();        // 模拟游戏进行画面的渲染
DWORD OnGameOver_D3D();         // 模拟游戏退出时的清理工作

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    WNDCLASSEXW wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYENGINE));
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    RegisterClassExW(&wcex);

    hInst = hInstance; // 将实例句柄存储在全局变量中

    HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
        600, 300, 800, 600, nullptr, nullptr, hInstance, nullptr);
    if (!hWnd) return 0;

    g_hMainWnd = hWnd;
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    //OnGameInit_GDI();
    if (!OnGameInit_D3D())return 0;

    DWORD dwFPS = 0;                        // 帧率
    DWORD dwLastTime = GetTickCount();      // 上一次渲染时间
    DWORD dwNowTime = 0;                    // 当前渲染时间
    DWORD dwLastFPSTime = dwLastTime;       // 保存最后次计算FPS的时间
    DWORD dwDelta = 0;                      // 每帧的运行时间

    LARGE_INTEGER nLast;                    // 精确定时
    LARGE_INTEGER nNow;
    LARGE_INTEGER _animationInterval;
    LARGE_INTEGER freq;
    QueryPerformanceFrequency(&freq);
    _animationInterval.QuadPart = freq.QuadPart*1.0 / 60;
    QueryPerformanceCounter(&nLast);

    MSG msg = { 0 };
    while (TRUE)// 此处 PeekMessage 与 GetMessage
    {
        if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))// 无论消息队列中是否有消息,都进行探测
        {
            if (WM_QUIT == msg.message)
                break;
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        QueryPerformanceCounter(&nNow);
        dwFPS++;
        if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
        {
            //OnGameRender_GDI();
            OnGameRender_D3D();
            nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % _animationInterval.QuadPart);
            if (dwFPS)
            {
                char szTitle[32];
                sprintf(szTitle, "游戏引擎 - FPS:%d", dwFPS);
                SetWindowTextA(g_hMainWnd, szTitle);
                dwFPS = 0;
            }
        }
        Sleep(1);
        // 使用GetTickCount控制帧率
//      OnGameRender_GDI();
//      OnGameRender_D3D();
//      dwFPS++;
//      dwNowTime = GetTickCount();
//      dwDelta = dwNowTime - dwLastTime; // 计算本帧的运行时间
//      // 控制每一帧在10ms左右
//      if (dwDelta < 20)
//      {
//          Sleep(20 - dwDelta);
//      }
// 
//      if ((dwNowTime - dwLastFPSTime) > 1000)
//      {
//          char szTitle[32];
//          if (dwFPS)
//          {
//              sprintf(szTitle, "游戏引擎 - FPS:%d", dwFPS);
//              SetWindowTextA(g_hMainWnd, szTitle);
//              dwLastFPSTime = dwNowTime;
//              dwFPS = 0;
//          }
//      }
//      dwLastTime = dwNowTime;           // 保存上一次更新的时间 
    }
    //OnGameOver_GDI();
    OnGameOver_D3D();

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CLOSE:
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    case WM_KEYDOWN:
        g_Key[wParam] = 1;
        break;
    case WM_KEYUP:
        g_Key[wParam] = 0;
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// 计算并获取0~dwBase的随机值
DWORD GetRand(DWORD dwBase)
{
    DWORD result = 0;
    __asm {
        rdtsc       // 取CPU执行的指令数
        mov result,eax
    }
    return result % dwBase;
}

DWORD OnGameInit_GDI()
{
    RECT rc;
    GetWindowRect(g_hMainWnd, &rc);
    nWidth = rc.right - rc.left;
    nHeight = rc.bottom - rc.top;
    return 0;
}
DWORD OnGameRender_GDI()
{
    if (KEYDOWN(VK_ESCAPE))
    {
        SendMessage(g_hMainWnd, WM_CLOSE, 0, 0);
    }
    HDC hdc = GetDC(g_hMainWnd);
    HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
    SelectObject(hdc, hPen);
    MoveToEx(hdc, GetRand(nWidth), GetRand(nHeight), NULL);
    LineTo(hdc, GetRand(nWidth), GetRand(nHeight));

    DeleteObject(hPen);
    ReleaseDC(g_hMainWnd,hdc);

    return 0;
}
DWORD OnGameOver_GDI()
{
    return 0;
}

bool OnGameInit_D3D()
{
    // 初始化Direct3D
    g_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
    if (NULL == g_pD3D)
    {
        MessageBox(g_hMainWnd, _T("Init Direct3D failed!"), _T("Error"), MB_OK | MB_ICONERROR);
        return false;
    }

    RECT rc;
    GetWindowRect(g_hMainWnd, &rc);
    nWidth = rc.right - rc.left;
    nHeight = rc.bottom - rc.top;

    D3DDISPLAYMODE displayMode;
    if (FAILED(g_pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode)))
        return false;
    // 设置Direct3D的属性
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = displayMode.Format;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferWidth = nWidth;
    d3dpp.BackBufferHeight = nHeight;
    d3dpp.hDeviceWindow = g_hMainWnd;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

    // 按要求建立Direct3D设备
    if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hMainWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pDev)))
    {
        int err1 = E_FAIL;
        int err = GetLastError();
        MessageBox(g_hMainWnd, _T("CreateDevice failed!"), _T("Error"), MB_OK | MB_ICONERROR);
        return false;
    }
    //D3DERR_DEVICELOST D3DERR_INVALIDCALL D3DERR_NOTAVAILABLE D3DERR_OUTOFVIDEOMEMORY
    srand(time(NULL));
    // 将背景色设置为黑色
    g_pDev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    // 获取后台渲染指针
    if (FAILED(g_pDev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackBuffer)))
        return false;

    // 建立离屏表面 (类似GDI双缓存)
    if(FAILED(g_pDev->CreateOffscreenPlainSurface(nWidth,nHeight,displayMode.Format,
        D3DPOOL_DEFAULT,&g_pSurface,NULL)))
        return false;

    return true;
}

bool OnGameRender_D3D()
{
    if (KEYDOWN(VK_ESCAPE))
        SendMessage(g_hMainWnd, WM_CLOSE, 0, 0);

    // 确认Direct3D设备
    if (!g_pDev) return false;

    // 开始渲染
    if (g_pDev->BeginScene())
    {
        // 将离屏幕表面填充随机颜色
        int r = rand() % 255;
        int g = rand() % 255;
        int b = rand() % 255;
        g_pDev->ColorFill(g_pSurface, NULL, D3DCOLOR_XRGB(r, g, b));

        // 画离屏表面到后台g_psurface的指定区域
        RECT rc;
        rc.left = rand() % nWidth / 2;
        rc.right = rc.left + rand() % nWidth / 2;
        rc.top = rand() % nHeight;
        rc.bottom = rc.top + rand() % nHeight / 2;
        g_pDev->StretchRect(g_pSurface, NULL, g_pBackBuffer, &rc, D3DTEXF_NONE);

        // 定制渲染
        g_pDev->EndScene();

        // 完成后台画面与前台的交互
        g_pDev->Present(NULL, NULL, NULL, NULL);
    }

    return 0;
}

DWORD OnGameOver_D3D()
{
    return 0;
}

源码VS2015
本文难免有所错误,如有问题欢迎留言。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值