注释
本主题是 使用 DirectX 教程系列创建简单的通用 Windows 平台(UWP)游戏的一部分。 该链接中的主题设置序列的上下文。
开发游戏的第一步是在 Microsoft Visual Studio 中创建项目。 在专门为游戏开发配置项目后,以后可以将其重新用作一种模板。
目标
- 使用项目模板在 Visual Studio 中创建新项目。
- 通过检查 App 类的源文件,了解游戏的入口点和初始化。
- 查看游戏循环。
- 查看项目的 package.appxmanifest 文件。
在 Visual Studio 中创建新项目
注释
有关设置 Visual Studio 进行 C++/WinRT 开发的信息(包括安装和使用 C++/WinRT Visual Studio 扩展(VSIX)和 NuGet 包(它们同时提供项目模板和生成支持),请参阅 Visual Studio 对 C++/WinRT的支持。
首先安装(或更新到)最新版本的 C++/WinRT Visual Studio 扩展(VSIX):请参阅上面的说明。 然后,在 Visual Studio 中,基于 核心应用(C++/WinRT) 项目模板创建新项目。 以 Windows SDK 的最新正式可用版本(即非预览版)为目标。
查看 App 类,了解 IFrameworkViewSource 和 IFrameworkView
在 Core App 项目中,打开源代码文件 App.cpp
。 在这里是 App 类的实现,它表示应用及其生命周期。 当然,在这种情况下,我们知道应用是一个游戏。 但是,我们将它称为 应用,以便更普遍地讨论通用 Windows 平台(UWP)应用如何初始化。
wWinMain 函数
wWinMain 函数是应用的入口点。 以下是 wWinMain 的外观(来自 App.cpp
)。
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
CoreApplication::Run(winrt::make<App>());
}
我们创建一个 App 类的实例(这是唯一创建的 App 的实例),并将其传递给静态 CoreApplication.Run 方法。 请注意,CoreApplication.Run 需要 IFrameworkViewSource 接口。 因此,App 类需要实现该接口。
本主题的后续两节介绍了 IFrameworkViewSource 和 IFrameworkView 接口。 这些接口(以及 CoreApplication.Run)表示应用向 Windows 提供 视图提供程序的方法。 Windows 使用该视图提供程序将应用与 Windows shell 连接,以便你可以处理应用程序生命周期事件。
IFrameworkViewSource 接口
App 类确实实现了 IFrameworkViewSource,如下面的列表所示。
struct App : winrt::implements<App, IFrameworkViewSource, IFrameworkView>
{
...
IFrameworkView CreateView()
{
return *this;
}
...
}
实现 IFrameworkViewSource 的对象是一个 视图提供者工厂 对象。 该对象的职责是制造和返回 视图提供者 对象。
IFrameworkViewSource 具有 IFrameworkViewSource::CreateView的单个方法。 Windows 在传递给 CoreApplication.Run的对象上调用该函数。 如上所示,该方法的 App::CreateView 实现返回 *this
。 换句话说,App 对象返回自身。 由于
IFrameworkView 接口
实现 IFrameworkView 的对象是 视图提供程序 对象。 现在,我们已经为 Windows 提供了视图提供程序。 这是我们在 wWinMain中创建的同一个 App 对象。 因此,App 类既充当 视图提供程序工厂,又充当 视图提供程序。
现在,Windows 可以调用 App 类 IFrameworkView方法的实现。 在这些方法的实现中,你的应用有机会执行初始化等任务,开始加载所需的资源,连接相应的事件处理程序,并接收应用将用于显示其输出的 CoreWindow。
你的 IFrameworkView 方法的实现将按照下面所示的顺序被调用。
- 初始化
- SetWindow
- 加载
- 将引发 CoreApplicationView::Activated 事件。 因此,如果已注册处理该事件(可选),则此时将调用 OnActivated 处理程序。
- 运行
- 取消初始化
下面是 App 类(App.cpp
)的框架,其中显示了这些方法的签名。
struct App : winrt::implements<App, IFrameworkViewSource, IFrameworkView>
{
...
void Initialize(Windows::ApplicationModel::Core::CoreApplicationView const& applicationView) { ... }
void SetWindow(Windows::UI::Core::CoreWindow const& window) { ... }
void Load(winrt::hstring const& entryPoint) { ... }
void OnActivated(
Windows::ApplicationModel::Core::CoreApplicationView const& applicationView,
Windows::ApplicationModel::Activation::IActivatedEventArgs const& args) { ... }
void Run() { ... }
void Uninitialize() { ... }
...
}
这只是一段关于 IFrameworkView的简介。 我们将在 定义游戏的 UWP 应用框架中详细了解这些方法以及如何实现它们。
整理项目
从项目模板创建的 Core App 项目包含此时我们应该整理的功能。 之后,我们可以使用该项目重新创建打靶游戏(Simple3DGameDX)。 对 中的 App.cpp
类进行以下更改。
- 删除其数据成员。
- 删除 OnPointerPressed、OnPointerMoved和 AddVisual
- 从 SetWindow
中删除代码。
该项目将编译并运行,但它只会在客户区中显示纯色。
游戏循环
若要了解游戏循环的外观,请查看下载的 Simple3DGameDX 示例游戏的源代码。
App 类有一个名为 m_main的数据成员,其类型为 GameMain。 这个成员在 App::Run 中如下所示使用。
void Run()
{
m_main->Run();
}
可以在 中找到 GameMain.cpp
。 这是游戏的主要循环,下面是一个非常粗略的概要,展示了其中最重要的特征。
void GameMain::Run()
{
while (!m_windowClosed)
{
if (m_visible)
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
Update();
m_renderer->Render();
m_deviceResources->Present();
}
else
{
CoreWindow::GetForCurrentThread().Dispatcher().ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
}
}
下面简要介绍了这个主游戏循环的作用。
如果游戏的窗口未关闭,请调度所有事件,更新计时器,然后呈现并显示图形管道的结果。 关于这些担忧,还有更多需要讨论的内容,我们将在以下几个主题中进行讨论:定义游戏的 UWP 应用框架,渲染框架 I:渲染入门,以及 渲染框架 II:游戏渲染。 但这是 UWP DirectX 游戏的基本代码结构。
查看并更新 package.appxmanifest 文件
Package.appxmanifest 文件包含有关 UWP 项目的元数据。 这些元数据用于打包和启动游戏,以及提交到 Microsoft 应用商店。 该文件还包含重要信息,玩家的系统用来访问游戏运行所需的系统资源。
通过在解决方案资源管理器中双击
有关 package.appxmanifest 文件和打包的信息,请参阅 清单设计器。 目前,请查看“功能”选项卡,并查看提供的选项。
如果未选择游戏使用的功能,例如访问全球高分板的 Internet,则无法访问相应的资源或功能。 创建新游戏时,请确保选择游戏调用的 API 所需的任何功能。
现在,让我们看看 Simple3DGameDX 示例游戏附带的其余文件。
查看其他重要库和源代码文件
如果你确实要为自己创建一种游戏项目模板,以便你可以将其重新用作未来项目的起点,则需要将 GameMain.h
和 GameMain.cpp
从下载的 Simple3DGameDX 项目中复制,并将其添加到新的 Core App 项目中。 研究这些文件,了解其用途,并删除特定于 Simple3DGameDX的任何内容。 此外,请将任何依赖于您尚未复制的代码的内容注释掉。 按照示例,GameMain.h
取决于 GameRenderer.h
。 将更多文件从 simple3DGameDX 复制出来时,你将能够取消注释。
下面简要介绍了 Simple3DGameDX 中的一些文件,如果你正在制作模板,它们将会非常有用。 无论如何,这些对于理解 Simple3DGameDX 本身的工作原理同样重要。
源文件 | 文件文件夹 | DESCRIPTION |
---|---|---|
DeviceResources.h/.cpp | 公用事业 | 定义 DeviceResources 类,该类控制所有 DirectX 设备资源。 还定义 IDeviceNotify 接口,用于通知应用程序图形适配器设备已丢失或重新创建。 |
DirectXSample.h | 公用事业 | 实现工具函数,例如 ConvertDipsToPixels。 ConvertDipsToPixels 将设备无关像素(DIP)的长度转换为物理像素长度。 |
GameTimer.h/.cpp | 公用事业 | 定义适用于游戏或交互式呈现应用的高分辨率计时器。 |
GameRenderer.h/.cpp | 渲染 | 定义 GameRenderer 类,该类实现一个基本的渲染流水线。 |
GameHud.h/.cpp | 渲染 | 定义一个类,使用 Direct2D 和 DirectWrite 渲染游戏的 HUD(抬头显示)。 |
VertexShader.hlsl 和 VertexShaderFlat.hlsl | 着色器 | 包含用于简单顶点着色器的高阶着色器语言(HLSL)代码。 |
PixelShader.hlsl 和 PixelShaderFlat.hlsl | 着色器 | 包含用于基本像素着色器的 HLSL(高级着色语言)代码。 |
ConstantBuffers.hlsli | 着色器 | 包含常量缓冲区和着色器结构的数据结构定义,这些结构用于将模型视图投影(MVP)矩阵和每个顶点数据传递到顶点着色器。 |
pch.h/.cpp | 无 | 包含常见的C++/WinRT、Windows 和 DirectX 包括。 |
后续步骤
此时,我们演示了如何为 DirectX 游戏创建新的 UWP 项目、查看其中的一些部分,并开始考虑如何将该项目转换为游戏的可重用模板。 我们还考察了 Simple3DGameDX 示例游戏中一些关键的部分。
下一部分是 定义游戏的 UWP 应用框架。 我们将更仔细地了解 Simple3DGameDX 的工作原理。