设置游戏项目
注意
本主题是使用 DirectX 创建简单的通用 Windows 平台 (UWP) 游戏教程系列的一部分。 此链接上的主题设置了该系列的上下文。
开发游戏的第一步是在 Microsoft Visual Studio 中创建一个项目。 为游戏开发专门配置项目后,可以在以后将其重新用作模板类型。
目标
- 使用项目模板在 Visual Studio 中创建新项目。
- 通过检查 App 类的源文件来了解游戏的入口点和初始化。
- 查看游戏循环。
- 检查项目的 package.appxmanifest 文件。
在 Visual Studio 中创建新项目
注意
有关设置 Visual Studio 以进行 C++/WinRT 部署的信息,包括安装和使用 C++/WinRT Visual Studio 扩展 (VSIX) 和 NuGet 包(两者共同提供项目模板,并生成支持)的信息,请参阅适用于 C++/WinRT 的 Visual Studio 支持。
首先安装(或更新到)C++/WinRT Visual Studio 扩展 (VSIX) 的最新版本;请参阅上述说明。 然后在 Visual Studio 中,基于“核心应用(C++/WinRT)”项目模板创建新项目。 面向 Windows SDK 的最新正式发布(非预览)版本。
查看 App 类以了解 IFrameworkViewSource 和 IFrameworkView
在核心应用项目中,打开源代码文件 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 对象会返回自己。 由于 IFrameworkViewSource::CreateView 的返回值类型为 IFrameworkView,因此 App 类也需要实现 该接口。 你可以看到它确实在上面的列表中。
IFrameworkView 接口
实现 IFrameworkView 的对象是视图提供程序对象。 我们现在向 Windows 提供了该视图提供程序。 这便是我们在 wWinMain 中创建的同一个 App 对象。 因此,App 类同时用作视图提供程序工厂和视图提供程序。
现在 Windows 可以调用 IFrameworkView 方法的 App 类实现。 在这些方法的实现中,应用有机会执行一些任务(如初始化)、开始加载所需的资源、连接相应的事件处理程序,以及接收应用将用于显示其输出的 CoreWindow。
IFrameworkView 方法的实现按下面所示的顺序进行调用。
- 初始化
- SetWindow
- 加载
- 引发 CoreApplicationView::Activated 事件。 因此,如果(可选)注册了以处理该事件,则此时会调用 OnActivated 处理程序。
- 运行
- Uninitialize
下面是 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 应用框架中,我们更详细地介绍了这些方法以及如何实现它们。
整理项目
从项目模板创建的核心应用项目包含我们应该在此时进行整理的功能。 在此之后,可以使用项目重新创建射击场游戏 (Simple3DGameDX)。 对 App.cpp
中的 App 类进行以下更改。
- 删除其数据成员。
- 删除 OnPointerPressed、OnPointerMoved 和 AddVisual
- 删除 SetWindow 中的代码。
项目会生成并运行,但它在客户端区域中仅显示纯色。
游戏循环
若要了解游戏循环的内容,请查看下载的 Simple3DGameDX 示例游戏的源代码。
App 类有一个名为 m_main 的数据成员,其类型为 GameMain。 该成员在 App::Run 中使用,如下所示。
void Run()
{
m_main->Run();
}
可以在 GameMain.cpp
中找到 GameMain::Run。 这是游戏的主循环,此处是非常粗略的概要,其中显示了最重要的功能。
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 Store。 该文件还包含玩家系统用于提供对运行游戏所需的系统资源的访问权限的重要信息。
通过在“解决方案资源管理器”中双击 package.appxmanifest 文件启动“清单设计器”。
有关 package.appxmanifest 文件和打包的详细信息,请参阅清单设计器。 现在,请看一下“功能”选项卡并查看提供的选项。
如果不选择游戏使用的功能(如用于全球高分榜的“Internet”),你将无法访问相应的资源和功能。 创建新游戏时,请确保选择了游戏调用的 API 所需的所有功能。
现在,我们看一下 Simple3DGameDX 示例游戏附带的其他文件。
查看其他重要库和源代码文件
如果你确实想要为自己创建一种游戏项目模板,以便你可以重复使用该模板作为作为将来项目的起点,则你需要从下载的 Simple3DGameDX 项目中复制出 GameMain.h
和 GameMain.cpp
,并将这些内容添加到新的核心应用项目中。 研究这些文件,了解其作用,并删除任何特定于 Simple3DGameDX 的内容。 此外,注释掉依赖于尚未复制的代码的任何内容。 仅仅举个例子,GameMain.h
依赖于 GameRenderer.h
。 在从 Simple3DGameDX 复制出更多文件时,能够取消注释。
下面是有关 Simple3DGameDX 中的某些文件的简要调查,你会发现模板(如果你要创建一个)中包含这些文件会十分有用。 在任何情况下,这些内容对于了解 Simple3DGameDX 本身的工作方式同样重要。
源文件 | 文件文件夹 | 说明 |
---|---|---|
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 的工作方式。