扩展示例游戏Extend the sample game

备注

本主题是 使用 DirectX 教程系列 (UWP) 游戏创建简单通用 Windows 平台 的一部分。This topic is part of the Create a simple Universal Windows Platform (UWP) game with DirectX tutorial series. 该链接上的主题设置了序列的上下文。The topic at that link sets the context for the series.

此时,我们已经介绍了基本的通用 Windows 平台 (UWP) DirectX 3D 游戏的关键组件。At this point we've covered the key components of a basic Universal Windows Platform (UWP) DirectX 3D game. 您可以为游戏设置框架,包括视图提供程序和渲染管道,并实现基本游戏循环。You can set up the framework for a game, including the view-provider and rendering pipeline, and implement a basic game loop. 还可以创建基本的用户界面覆盖层、合并声音、实现控件。You can also create a basic user interface overlay, incorporate sounds, and implement controls. 你已经踏上了创建自己游戏的旅程,如果你需要更多帮助和信息,请查看这些资源。You're on your way to creating a game of your own, but if you need more help and info, check out these resources.

将 XAML 用于覆盖层Using XAML for the overlay

我们深入讨论的一种替代方法是使用 XAML 而不是 Direct2D 进行覆盖。One alternative that we didn't discuss in depth is the use of XAML instead of Direct2D for the overlay. 与 Direct2D 相比,XAML 在绘制用户界面元素方面有许多优势。XAML has many benefits over Direct2D for drawing user interface elements. 最重要的一点是它可以更方便地将 Windows 10 外观和感觉融入到 DirectX 游戏中。The most important benefit is that it makes incorporating the Windows 10 look and feel into your DirectX game more convenient. 许多用于定义 UWP 应用的常用元素、 样式和行为都紧密集成到 XAML 模型中,大幅减少了游戏开发人员的实现工作。Many of the common elements, styles, and behaviors that define a UWP app are tightly integrated into the XAML model, making it far less work for a game developer to implement. 如果你自己设计的游戏有一个复杂的用户界面,请考虑使用 XAML 代替 Direct2D。If your own game design has a complicated user interface, consider using XAML instead of Direct2D.

使用 XAML,我们可以制作一个外观与之前制作的 Direct2D 界面类似的游戏界面。With XAML, we can make a game interface that looks similar to the Direct2D one made earlier.

XAMLXAML

XAML 覆盖

Direct2DDirect2D

D2D 覆盖

虽然它们的最终结果相似,但实现 Direct2D 和 XAML 界面之间很多区别。While they have similar end results, there are a number of differences between implementing Direct2D and XAML interfaces.

功能Feature XAMLXAML Direct2DDirect2D
定义覆盖Defining overlay 在 XAML 文件 \*.xaml 中定义。Defined in a XAML file, \*.xaml. 在了解了 XAML 后,与 Direct2D 相比,创建和配置更复杂的覆盖变得更加简单。Once understanding XAML, creating and configuring more complicated overlays are made simpiler when compared to Direct2D. 定义为手动放置并写入 Direct2D 目标缓冲区的 Direct2D 基元和 DirectWrite 字符串的集合。Defined as a collection of Direct2D primitives and DirectWrite strings manually placed and written to a Direct2D target buffer.
用户界面元素User interface elements XAML 用户界面元素来自属于 Windows 运行时 XAML API 一部分的标准化元素,其中包括 Windows::UI::XamlWindows::UI::Xaml::ControlsXAML user interface elements come from standardized elements that are part of the Windows Runtime XAML APIs, including Windows::UI::Xaml and Windows::UI::Xaml::Controls. 处理 XAML 用户界面元素行为的代码在代码隐藏文件 Main.xaml.cpp 中定义。The code that handles the behavior of the XAML user interface elements is defined in a codebehind file, Main.xaml.cpp. 简单的形状可以像矩形和省略号一样绘制。Simple shapes can be drawn like rectangles and ellipses.
调整窗口大小Window resizing 自然地处理调整大小和视图状态更改事件,并相应地转换覆盖层Naturally handles resize and view state change events, transforming the overlay accordingly 需要手动指定如何重绘覆盖层的组件。Need to manually specify how to redraw the overlay's components.

另一个较大的区别是交换链Another big difference involves the swap chain. 你不必将交换链附加到 Windows::UI::Core::CoreWindow 对象。You don't have to attach the swap chain to a Windows::UI::Core::CoreWindow object. 而在构建新的 SwapChainPanel 对象时,合并 XAML 的 DirectX 应用将关联一个交换链。Instead, a DirectX app that incorporates XAML associates a swap chain when a new SwapChainPanel object is constructed.

以下代码段演示如何在 DirectXPage.xaml 文件中声明 SwapChainPanel 的 XAML。The following snippet show how to declare XAML for the SwapChainPanel in the DirectXPage.xaml file.

<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 属性。The SwapChainPanel object is set as the Content property of the current window object created at launch by the app singleton.

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,从而向其传递配置的交换链。To attach the configured swap chain to the SwapChainPanel instance defined by your XAML, you must obtain a pointer to the underlying native ISwapChainPanelNative interface implementation and call ISwapChainPanelNative::SetSwapChain on it, passing it your configured swap chain.

以下 DX::DeviceResources::CreateWindowSizeDependentResources 的代码段详细介绍了 DirectX/XAML 互操作的这个方面:The following snippet from DX::DeviceResources::CreateWindowSizeDependentResources details this for DirectX/XAML interop:

        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 互操作For more info about this process, see DirectX and XAML interop.

示例Sample

若要下载使用 XAML 进行覆盖的此游戏的版本,请参阅 Direct3D 获取 示例游戏 (XAML) To download the version of this game that uses XAML for the overlay, go to the Direct3D shooting sample game (XAML).

与在本主题的其余部分中讨论的示例游戏的版本不同,XAML 版本在app.xamlDirectXPage文件中定义其框架,而不是分别在GameInfoOverlay 和中定义App.cppUnlike the version of the sample game discussed in the rest of these topics, the XAML version defines its framework in the App.xaml.cpp and DirectXPage.xaml.cpp files, instead of App.cpp and GameInfoOverlay.cpp, respectively.