上一节:https://blog.csdn.net/z736248591/article/details/122658701
搭建引擎框架
回顾
上一章节,我们创建了一个空的窗口,这一章节,我们搭建引擎框架来封装窗口显示和渲染。
框架介绍
首先来介绍四个最重要的全局类:
- Director:负责控制整个游戏。
- Graphics:负责处理游戏的渲染部分。
- Input:负责处理用户的所有输入。
- Audio:负责全局管理所有的针对音频的操作。
本节主要介绍Graphics渲染部分。
创建
创建Graphics类的头文件和源文件。
声明
在Graphics.h 内引入Direct2D的头文件。
#include <windows.h>
#include <d2d1_3.h>
#include <wincodec.h>
d2d1_3为Windows上Direct2D 1.3版本的头文件,具体可以查看MSDN上更新的内容。
引入STL头文件。
#include <memory>
#include <string>
#include <iostream>
链接Direct2D的库文件。
#pragma comment(lib, "d2d1.lib")
声明类成员属性。
class Graphics
{
public:
static void Init(int width, int height,const std::wstring &title = L"");
static void Render(std::shared_ptr<Scene> scene);
static void Dispose();
private:
inline static HWND hwnd = NULL;
inline static ID2D1Factory* d2dFactory = NULL;
inline static ID2D1HwndRenderTarget* renderTarget = NULL;
static void InitWindows(int width, int height,const std::wstring& title = L"");
static void InitD2D();
};
初始化
需要对渲染初始化,主要的任务为创建窗口和初始化Direct2D。
void Graphics::Init(int width, int height, const std::wstring& title)
{
InitWindows(width, height, title);
InitD2D();
}
窗口创建为上一节的内容,这里不再一一介绍。
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
void Graphics::InitWindows(int width, int height, const std::wstring& title)
{
HINSTANCE hInstance;
hInstance = GetModuleHandle(NULL);
WNDCLASS wndClass{};
wndClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
wndClass.lpfnWndProc = WindowProc;
wndClass.lpszClassName = L"SGE";
wndClass.hInstance = hInstance;
wndClass.style = CS_OWNDC;
RegisterClass(&wndClass);
HWND hwnd = CreateWindow(
L"SGE",
L"The Seed Game Engine",
WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE,
38,
20,
width,
height,
NULL,
NULL,
hInstance,
NULL);
if (FAILED(hwnd))
{
std::wcout << L"创建窗口出错!" << std::endl;
throw;
}
Graphics::hwnd = hwnd;
RECT rc;
GetClientRect(hwnd, &rc);
MoveWindow(hwnd, 38, 20, width + width - rc.right, height + height - rc.bottom, true);
}
初始化Direct2D。
void Graphics::InitD2D()
{
HRESULT hr;
在Debug模式下打开调试可视层。
D2D1_FACTORY_OPTIONS options{};
#if defined(_DEBUG)
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif
初始化D2D1Factory类,以后操作均要通过这个类来创建D2D资源对象。
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);
if (FAILED(hr))
{
std::wcout << L"创建D2D工厂失败。" << std::endl;
throw;
}
创建绘制渲染区域。
RECT rc;
GetClientRect(hwnd, &rc);
hr = d2dFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),D2D1::HwndRenderTargetProperties(hwnd,D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),&renderTarget);
if (FAILED(hr))
{
std::wcout << L"创建渲染区域失败!" << std::endl;
throw;
}
渲染
Render 函数负责渲染内容,scene 参数为场景类对象,由场景类来组织内容,具体的实现见下一节。
void Graphics::Render(std::shared_ptr<Scene> scene)
{
准备开始绘制
renderTarget->BeginDraw();
只有调用了BeginDraw 才能开始绘图。
使用黑色背景色来清空绘图区域
static D2D1::ColorF blackgroundColor = D2D1::ColorF::Black;
renderTarget->Clear(blackgroundColor);
绘制内容
scene->Render();
结束绘制
HRESULT hr = renderTarget->EndDraw();
if (FAILED(hr))
{
std::wcout << L"绘图错误!" << std::endl;
throw;
}
销毁
当游戏结束运行的时候需要销毁之前申请的资源。
这里定义一个安全释放资源的宏。
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
销毁所有申请的资源。
void Graphics::Dispose()
{
SAFE_RELEASE(renderTarget);
SAFE_RELEASE(d2dFactory);
}
完整代码
Graphics.h
#pragma once
#include <windows.h>
#include <d2d1_3.h>
#include <wincodec.h>
#include <memory>
#include <string>
#include <iostream>
#include "Scene.h"
#pragma comment(lib, "d2d1.lib")
namespace sge {
class Graphics
{
public:
static void Init(int width, int height,const std::wstring &title = L"");
static void Render(std::shared_ptr<Scene> scene);
static void Dispose();
private:
inline static HWND hwnd = NULL;
inline static ID2D1Factory* d2dFactory = NULL;
inline static ID2D1HwndRenderTarget* renderTarget = NULL;
static void InitWindows(int width, int height,const std::wstring& title = L"");
static void InitD2D();
};
}
Graphics.cpp
#include "Graphics.h"
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
namespace sge {
void Graphics::Init(int width, int height, const std::wstring& title)
{
InitWindows(width, height, title);
InitD2D();
}
void Graphics::Render(std::shared_ptr<Scene> scene)
{
renderTarget->BeginDraw();
static D2D1::ColorF blackgroundColor = D2D1::ColorF::Black;
renderTarget->Clear(blackgroundColor);
scene->Render();
HRESULT hr = renderTarget->EndDraw();
if (FAILED(hr))
{
std::wcout << L"绘图错误!" << std::endl;
throw;
}
}
void Graphics::Dispose()
{
SAFE_RELEASE(renderTarget);
SAFE_RELEASE(d2dFactory);
}
void Graphics::InitWindows(int width, int height, const std::wstring& title)
{
HINSTANCE hInstance;
hInstance = GetModuleHandle(NULL);
WNDCLASS wndClass{};
wndClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
wndClass.lpfnWndProc = WindowProc;
wndClass.lpszClassName = L"SGE";
wndClass.hInstance = hInstance;
wndClass.style = CS_OWNDC;
RegisterClass(&wndClass);
HWND hwnd = CreateWindow(
L"SGE",
L"The Seed Game Engine",
WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE,
38,
20,
width,
height,
NULL,
NULL,
hInstance,
NULL);
if (FAILED(hwnd))
{
std::wcout << L"创建窗口出错!" << std::endl;
throw;
}
Graphics::hwnd = hwnd;
RECT rc;
GetClientRect(hwnd, &rc);
MoveWindow(hwnd, 38, 20, width + width - rc.right, height + height - rc.bottom, true);
}
void Graphics::InitD2D()
{
HRESULT hr;
D2D1_FACTORY_OPTIONS options{};
#if defined(_DEBUG)
options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory);
if (FAILED(hr))
{
std::wcout << L"创建D2D工厂失败。" << std::endl;
throw;
}
RECT rc;
GetClientRect(hwnd, &rc);
hr = d2dFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hwnd,
D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),
&renderTarget);
if (FAILED(hr))
{
std::wcout << L"创建渲染区域失败!" << std::endl;
throw;
}
}
}
总结
本节主要介绍了游戏引擎框架最主要的四个类,以及渲染部分的编写。下一节会继续介绍剩余未编写的部分。
|