[DirectX]Engine的第一步?控制台创建窗口及封装main函数

       看《Teach Yourself Game Programming with DirectX in 21 Days》真的快半年了,虽然有很长时间都花在项目上(主要是在对接大厂的SDK,那段时间真的快对接疯了),但至少从开始到现在有半年的时间了,真的看的有点累了,换个心情看起了GameEngine相关视频。最近也会开始将从《Teach Yourself Game Programming with DirectX in 21 Days》学到的内容发到博客上的。

************************************************************************************************************************************

       在看GameEngine相关视频时候,看到GLFW库可以在控制台程序中创建Window窗口,就去google了相关资料,发现是可以用控制台程序创建窗口的,就测试了下。
       Window创建的代码都封装在CSystem这个class中,其实创建Window窗口的代码都不想贴出来的,因为没啥东西,现在已经都不需要看书,完全能默写下来了╮( ̄▽ ̄)╭:
       CSystem.h:

#pragma once

#include <Windows.h>
#include <iostream>

namespace Engine
{
	class CSystem
	{
	public:
		CSystem();
		~CSystem();

		bool Initialize(const char* strName, int iWidth, int iHeight, bool bFullScreen);
		void Shutdown();
		void Run();

		virtual LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

	private:
		std::string m_strAppName;
		int m_iWidth, m_iHeight;
		bool m_bFullScreen;
		HINSTANCE m_appInstance;
		HWND m_hwnd;
	};

	static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

	static CSystem* m_pGlobalSystem = nullptr;

	// To be defined in CLIENT
	CSystem* CreateSystem();
}

       CSystem.cpp:

#include "Engine/CSystem.h"

namespace Engine
{
	CSystem::CSystem()
	{
		m_iWidth = 0;
		m_iHeight = 0;
		m_bFullScreen = false;
		m_appInstance = NULL;
		m_hwnd = NULL;
	}

	CSystem::~CSystem()
	{
		m_hwnd = NULL;
		m_appInstance = NULL;
		m_bFullScreen = false;
		m_iHeight = 0;
		m_iWidth = 0;

	}

	bool CSystem::Initialize(const char* strName, int iWidth, int iHeight, bool bFullScreen)
	{
		m_strAppName = strName;
		m_iWidth = iWidth;
		m_iHeight = iHeight;
		m_bFullScreen = bFullScreen;
		m_appInstance = GetModuleHandle(NULL);

		m_pGlobalSystem = this;

		WNDCLASSEX wndClass;
		memset(&wndClass, 0, sizeof(wndClass));
		wndClass.cbClsExtra = 0;
		wndClass.cbSize = sizeof(wndClass);
		wndClass.cbWndExtra = 0;
		wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
		wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
		wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
		wndClass.hIconSm = wndClass.hIcon;
		wndClass.hInstance = m_appInstance;
		wndClass.lpfnWndProc = WndProc;
		wndClass.lpszClassName = m_strAppName.c_str();
		wndClass.lpszMenuName = nullptr;
		wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

		if (!RegisterClassEx(&wndClass))
		{
			MessageBox(NULL, TEXT("RegisterClassEx function failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
			return false;
		}

		int screenWidth, screenHeight;
		int posX, posY;
		screenWidth = GetSystemMetrics(SM_CXSCREEN);
		screenHeight = GetSystemMetrics(SM_CYSCREEN);
		if (m_bFullScreen)
		{
			DEVMODE dmScreenSettings;
			memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
			dmScreenSettings.dmSize = sizeof(dmScreenSettings);
			dmScreenSettings.dmPanningWidth = screenWidth;
			dmScreenSettings.dmPanningWidth = screenHeight;
			dmScreenSettings.dmBitsPerPel = 32;
			dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
			ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);

			m_iWidth = screenWidth;
			m_iHeight = screenHeight;

			posX = posY = 0;
		}
		else
		{
			posX = (screenWidth - m_iWidth) / 2;
			posY = (screenHeight - m_iHeight) / 2;
		}

		m_hwnd = CreateWindowEx(
			WS_EX_APPWINDOW,
			wndClass.lpszClassName,
			wndClass.lpszClassName,
			WS_OVERLAPPEDWINDOW,
			posX, posY,
			m_iWidth, m_iHeight,
			NULL,
			NULL,
			m_appInstance,
			nullptr);

		if (!m_hwnd)
		{
			MessageBox(NULL, TEXT("CreateWindowEx function failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
			return false;
		}

		ShowWindow(m_hwnd, SW_SHOW);
		UpdateWindow(m_hwnd);
		SetFocus(m_hwnd);

		ShowCursor(true);

		return true;
	}

	void CSystem::Shutdown()
	{
		if (m_bFullScreen)
			ChangeDisplaySettings(nullptr, 0);

		DestroyWindow(m_hwnd);
		m_hwnd = NULL;

		UnregisterClass(m_strAppName.c_str(), m_appInstance);
		m_appInstance = NULL;

		m_pGlobalSystem = nullptr;
	}

	void CSystem::Run()
	{
		MSG msg;
		memset(&msg, 0, sizeof(msg));

		bool done = false;
		while (!done)
		{
			if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}

			if (WM_QUIT == msg.message)
				done = true;
			else
			{

			}
		}
	}

	LRESULT CALLBACK CSystem::MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
		return DefWindowProc(hwnd, msg, wParam, lParam);
	}

	LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
	{
		switch (msg)
		{
		case WM_CLOSE:
			PostQuitMessage(0);
			break;
		case WM_DESTROY:
			PostQuitMessage(0);
			break;
		}

		return m_pGlobalSystem->MessageHandler(hwnd, msg, wParam, lParam);
	}
}

       调用接口在EntryPoint.h:

#pragma once

#include "CSystem.h"

#ifdef ENGINE_PLATFORM_WINDOWS

extern Engine::CSystem* Engine::CreateSystem();

int main(int argc, char** argv)
{
	std::cout << "Engine: main begin" << std::endl;
	Engine::CSystem* pSystem = Engine::CreateSystem();

	pSystem->Run();
	pSystem->Shutdown();

	delete pSystem;
	pSystem = nullptr;

	std::cout << "Engine: main end" << std::endl;

	return 0;
}
#endif

       Engine.h:

#pragma once

// ---Entry Point----------------------
#include "Engine/EntryPoint.h"
// ------------------------------------

       如果是application程序的话,就可以直接运行了,但是在看GameEngine视频的时候学到个骚操作:把main函数封装到dll中。但可惜的是动态库不支持STL,一直报这个warning c4251:needs to have dll interface to be used by clients of class,虽然能解决,但是很麻烦,只好改成静态库。
       新建一个名称为Test的Project,添加头文件目录和库文件目录:

       为了配置方便,主要是多台电脑路径有可能不一样, 不想每次都去修改就将这些都配置到环境变量中去了,包括boost,DirectX9,JsonCpp等库都是这么玩的,方便管理。

     添加一个cpp文件,取名为Main.cpp:

#ifdef _DEBUG
#pragma comment(lib, "Debug/Engine.lib")
#else
#pragma comment(lib, "Release/Engine.lib")
#endif

#ifndef ENGINE_PLATFORM_WINDOWS
#define ENGINE_PLATFORM_WINDOWS
#endif

#include <Engine.h>

Engine::CSystem* Engine::CreateSystem()
{
	std::cout << "Test Project: CreateSystem begin" << std::endl;
	Engine::CSystem* pSystem = new Engine::CSystem();
	pSystem->Initialize("Test Project", 600, 480, false);
	std::cout << "Test Project: CreateSystem end" << std::endl;
	return pSystem;
}

#ifndef ENGINE_PLATFORM_WINDOWS

int main()
{
	std::cout << "Test Project: Hello, world" << std::endl;
	return 0;
}

#endif

       Engine::CSystem* Engine::CreateSystem()方法只是为了可以修改一些参数添加的。其实Main.cpp中什么都不写,只写到#include <Engine.h>都是可以运行的,可以测试下。

       可以将#define ENGINE_PLATFORM_WINDOWS这行代码注释掉,就会看到比较好玩的东西:注释掉后调用的是Main.cpp中的main函数,只有一个控制台。取消注释后就是调用静态库中的main函数,显示一个控制台和一个窗口:

      哎,差点漏了一个比较重要的东西:GameEngine视频地址,油管上的,有2个系列,我都刚开始看,最新的感觉比较难,好像还在更新中。最重要的是OpenGL的,OpenGL的,OpenGL的,重要的事情要说3遍,虽然没学过OpenGL,应该也有参考价值。

GameEngine Series1

GameEngine Series2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值