扩展示例游戏
注意
本主题是使用 DirectX 创建简单的通用 Windows 平台 (UWP) 游戏教程系列的一部分。 此链接上的主题设置了该系列的上下文。
要下载为覆盖层使用 XAML 的此游戏的版本,请参阅 DirectX 和 XAML 游戏示例。 请务必阅读其中的自述文件,以了解有关生成示例的详细信息。
此时,我们已经介绍了基本的通用 Windows 平台 (UWP) DirectX 3D 游戏的关键组件。 你可以设置游戏的框架,包括视图提供程序和呈现管道,并实现基本的游戏循环。 还可以创建基本的用户界面覆盖层、合并声音、实现控件。 你已经踏上了创建自己游戏的旅程,如果你需要更多帮助和信息,请查看这些资源。
将 XAML 用于覆盖层
还有一种方法我们未深入讨论,即使用 XAML 代替 Direct2D 作为覆盖层。 与 Direct2D 相比,XAML 在绘制用户界面元素方面有许多优势。 最重要的一点是它可以更方便地将 Windows 10 外观和感觉融入到 DirectX 游戏中。 许多用于定义 UWP 应用的常用元素、 样式和行为都紧密集成到 XAML 模型中,大幅减少了游戏开发人员的实现工作。 如果你自己设计的游戏有一个复杂的用户界面,请考虑使用 XAML 代替 Direct2D。
使用 XAML,我们可以制作一个外观与之前制作的 Direct2D 界面类似的游戏界面。
XAML
Direct2D
虽然它们的最终结果相似,但实现 Direct2D 和 XAML 界面之间很多区别。
Feature | XAML | Direct2D |
---|---|---|
定义覆盖 | 在 XAML 文件 \*.xaml 中定义。 了解 XAML 后,与 Direct2D 相比,创建和配置更复杂的覆盖更加简单。 |
定义为手动放置并写入 Direct2D 目标缓冲区的 Direct2D 基元和 DirectWrite 字符串的集合。 |
用户界面元素 | XAML 用户界面元素来自属于 Windows 运行时 XAML API 一部分的标准化元素,其中包括 Windows::UI::Xaml 和 Windows::UI::Xaml::Controls。 处理 XAML 用户界面元素行为的代码在代码隐藏文件 Main.xaml.cpp 中定义。 | 简单的形状可以像矩形和省略号一样绘制。 |
调整窗口大小 | 自然地处理调整大小和视图状态更改事件,并相应地转换覆盖层 | 需要手动指定如何重绘覆盖层的组件。 |
另一个较大的区别是交换链。 你不必将交换链附加到 Windows::UI::Core::CoreWindow 对象。 而在构建新的 SwapChainPanel 对象时,合并 XAML 的 DirectX 应用将关联一个交换链。
以下代码段演示如何在 DirectXPage.xaml 文件中声明 SwapChainPanel 的 XAML。
<Page
x:Class="Simple3DGameXaml.DirectXPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Simple3DGameXaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<SwapChainPanel x:Name="DXSwapChainPanel">
<!-- ... XAML user controls and elements -->
</SwapChainPanel>
</Page>
SwapChainPanel 对象由应用单一实例设置为启动时创建的当前窗口对象的 Content 属性。
void App::OnLaunched(_In_ LaunchActivatedEventArgs^ /* args */)
{
m_mainPage = ref new DirectXPage();
Window::Current->Content = m_mainPage;
// Bring the application to the foreground so that it's visible
Window::Current->Activate();
}
若要将配置的交换链连接到 XAML 定义的 SwapChainPanel 实例,必须获取底层本机 ISwapChainPanelNative 接口实现的指针并对其调用 ISwapChainPanelNative::SetSwapChain,从而向其传递配置的交换链。
以下 DX::DeviceResources::CreateWindowSizeDependentResources 的代码段详细介绍了 DirectX/XAML 互操作的这个方面:
ComPtr<IDXGIDevice3> dxgiDevice;
DX::ThrowIfFailed(
m_d3dDevice.As(&dxgiDevice)
);
ComPtr<IDXGIAdapter> dxgiAdapter;
DX::ThrowIfFailed(
dxgiDevice->GetAdapter(&dxgiAdapter)
);
ComPtr<IDXGIFactory2> dxgiFactory;
DX::ThrowIfFailed(
dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
);
// When using XAML interop, the swap chain must be created for composition.
DX::ThrowIfFailed(
dxgiFactory->CreateSwapChainForComposition(
m_d3dDevice.Get(),
&swapChainDesc,
nullptr,
&m_swapChain
)
);
// Associate swap chain with SwapChainPanel
// UI changes will need to be dispatched back to the UI thread
m_swapChainPanel->Dispatcher->RunAsync(CoreDispatcherPriority::High, ref new DispatchedHandler([=]()
{
// Get backing native interface for SwapChainPanel
ComPtr<ISwapChainPanelNative> panelNative;
DX::ThrowIfFailed(
reinterpret_cast<IUnknown*>(m_swapChainPanel)->QueryInterface(IID_PPV_ARGS(&panelNative))
);
DX::ThrowIfFailed(
panelNative->SetSwapChain(m_swapChain.Get())
);
}, CallbackContext::Any));
// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
// ensures that the application will only render after each VSync, minimizing power consumption.
DX::ThrowIfFailed(
dxgiDevice->SetMaximumFrameLatency(1)
);
}
有关此过程的详细信息,请参阅 DirectX 和 XAML 互操作。
示例
要下载为覆盖层使用 XAML 的此游戏的版本,请参阅 DirectX 和 XAML 游戏示例。 请务必阅读其中的自述文件,以了解有关生成示例的详细信息。
与其余主题中讨论的示例游戏版本不同,XAML 版本分别在 App.xaml.cpp 和 DirectXPage.xaml.cpp 文件中定义其框架,而不是在 App.cpp 和 GameInfoOverlay.cpp 中。