2021SC@SDUSC
开源游戏引擎 Overload 代码模块分析 之 OvGame(七)—— Core(四)Application & Main.cpp
目录
前言
本篇是 OvGame 的 Core 的第四篇,也是 Core 的最后一篇,将探究其最后的 Application 部分。这部分的内容很少,所以本篇也将进一步探究完 OvGame 的最后内容 Main.cpp。
其中,Application 包含了同是 Core 的 Context 与 Game,如果读者已经有些遗忘、或是尚未了解过,请先前往 Core(一) 、Core(三) 阅读。
另外,若想先大致了解该引擎各个大模块,可前往笔者这篇相关文章查看。
若想了解 OvGame 大纲,可前往笔者这篇文章。
分析
1、Application
1.1 Application.h
1.1.1 头文件
#include "OvGame/Core/Context.h"
#include "OvGame/Core/Game.h"
该文件仅包含了前言中提及的两个头文件,请读者自行前往了解了解。
1.1.2 主要代码
主要代码是一个 Application 类,是 OvGame 模块的接口点,定义如下:
class Application
{
public:
/**
* Constructor
*/
Application();
/**
* Destructor
*/
~Application();
/**
* Run the app
*/
void Run();
/**
* Returns true if the app is running
*/
bool IsRunning() const;
private:
Context m_context;
Game m_game;
};
显然,作为一个综合接口,该类函数都是负责运行程序,变量也是老朋友 Context 和 Game,不多赘述。
1.2 Application.cpp
1.2.1 头文件
#include <OvTools/Time/Clock.h>
#include "OvGame/Core/Application.h"
该文件除了 Application.h,还引入了 Overload 的 OvTools 模块。巧合的是,笔者之前的文章探究过该模块,感兴趣的读者可以前往阅读。
1.2.2 主体代码
Application() 与 ~Application() 函数
OvGame::Core::Application::Application() :
m_game(m_context)
{
}
OvGame::Core::Application::~Application()
{
}
这两个分别是构造函数和析构函数,都没有定义具体代码,不多赘述。其中构造函数是用参数初始化表更新了 m_game。
IsRunning() 函数
bool OvGame::Core::Application::IsRunning() const
{
return !m_context.window->ShouldClose();
}
该函数负责判断是否在运行应用。m_context.window(窗口)的函数 ShouldClose() 能调用 GLFW 的 glfwWindowShouldClose() 得到窗口是否关闭的讯息真值并返回:要关闭为真,不关闭为假。所以,代码直接调用 ShouldClose() 并取反真值,再返回即可。
Run() 函数
void OvGame::Core::Application::Run()
{
OvTools::Time::Clock clock;
while (IsRunning())
{
m_game.PreUpdate();
m_game.Update(clock.GetDeltaTime());
m_game.PostUpdate();
clock.Update();
}
}
该函数负责运行应用。先声明一个 Clock 类对象记录时间;然后,利用上文的 IsRunning() 判断是否还在运行即没有关闭应用,是则进入 while 循环;接着,在 while 循环内,m_game 调用依次函数,进行从 PreUpdate() 启用输入和事件、经过 Update() 更新、到 PostUpdate() 结束输入输出缓存的一套逻辑更新;最后,clock 调用 Update() 更新时间记录。
至此,Application 的内容就全部探究完毕了。为什么这么快呢?是因为 Application 完全是一个使用者,几乎是应用其它类与功能函数来完成自己的任务。所以,如果想更多地了解 Application 的运行过程,需要读者们去认真阅读笔者在前言中提及的文章,以及这些文章提及的其它文章,挨个了解好背后封装好的各种函数。
另一方面,根据 Overload 的 OvGame 模块大纲,OvGame 模块的三个文件夹也都探究完毕了。不过,读者们如果没有了解好 OvGame 这些部分的封装功能以及嵌套调用关系,也可以继续前往最后一部分,OvGame 模块的 Main.cpp 文件。
2、Main.cpp
2.1 头文件
#include <OvRendering/Utils/Defines.h>
#include "OvGame/Core/Application.h"
该文件包含了上文的 Application 文件以及 Overload 的另一模块文件 OvRendering/Utils/Defines.h,该头文件和 GPU 相关。
2.2 主要代码
FORCE_DEDICATED_GPU
#ifdef _DEBUG
int main()
#else
#undef APIENTRY
#include "Windows.h"
INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
#endif
{
OvGame::Core::Application app;
app.Run();
return EXIT_SUCCESS;
}
首先,声明 FORCE_DEDICATED_GPU,强制独占 GPU;接着进入条件编译命令,此处的含义是选择要编译的函数名:
如果定义 _DEBUG 即进入 Debug 模式,则选择函数名为 int 型 main() ,没有参数;否则进行下一个判断:如果没有定义 API 接口,则引入 C++ 头文件 Windows.h(有关 Windows 系统),选择函数名为 INT(重定义前即 int)型 WinMain(),并加入多个有关应用程序信息的参数,其中用到的类型是 Windows 的 HINSTANCE(应用程序模块的实例)与 PSTR(相当于 C++ 的 char*)。
而不论哪个函数名,运行内容都是 “ #endif ” 之后的那段代码:先声明一个 app 应用类,再直接调用上文提及的 Run() 运行该应用程序。最后,当关闭该应用、退出 Run() 函数后,则返回 EXIT_SUCCESS 命令,退出并中止程序。
总结
现在,Application 与 main 函数的内容都探究完了,都是使用封装内容,并不复杂;另一方面,这也同样意味着 OvGame 的所有内容都探究完毕了。所以,下一篇,笔者将写一个 OvGame 模块的终篇总结,作为该系列的结尾。