Расширение образца игры

Примечание

Этот раздел является частью серии учебников Создание простой игры универсальная платформа Windows (UWP) с помощью DirectX. Раздел по этой ссылке задает контекст для ряда.

Чтобы скачать версию этой игры, которая использует XAML для наложения, см. пример игры DirectX и XAML. Не забудьте прочитать файл сведений, чтобы получить дополнительные сведения о создании примера.

Итак, вы уже знакомы с основными компонентами трехмерной игры универсальной платформы Windows (UWP) на базе DirectX. Вы можете настроить платформу для игры, включая поставщика представлений и конвейер отрисовки, а также реализовать базовый цикл игры. Вы также можете создать базовое наложение пользовательского интерфейса, добавить звуки и реализовать элементы управления. Вы практически готовы к созданию своей собственной игры, но если вам нужна дополнительная информация и помощь, воспользуйтесь ресурсами ниже.

Использование XAML для создания наложения

Одним из вариантов, который мы не обсуждали подробно, является использование XAML вместо Direct2D для наложения. С точки зрения рисования элементов пользовательского интерфейса XAML обеспечивает ряд преимуществ по сравнению с Direct2D. Главное преимущество заключается в том, что с помощью XAML проще придать вашей игре на базе DirectX внешний вид и удобство использования, характерные для Windows 10. Поскольку большое число общих элементов, стилей и функций, присущих приложениям UWP, интегрировано в модель XAML, задача разработчиков игр значительно облегчается. Если вы разрабатываете для своей игры сложный пользовательский интерфейс, советуем вам использовать XAML вместо Direct2D.

Используя XAML, можно сделать игру с интерфейсом, похожим на интерфейс на базе Direct2D, который мы создали раньше.

XAML

Наложение XAML

Direct2D

Наложение D2D

Несмотря на схожий конечный результат, между реализацией интерфейсов на базе Direct2D и XAML существует ряд различий.

Функция XAML Direct2D
Определение наложения Определяется в XAML-файле (\*.xaml). Как только вы разберетесь в XAML, создавать и конфигурировать сложные наложения будет проще, чем при использовании Direct2D. Определяется в виде коллекции примитивов Direct2D и строк DirectWrite, вручную помещаемых и записываемых в целевой буфер Direct2D.
Элементы пользовательского интерфейса Элементы пользовательского интерфейса на языке XAML происходят от стандартных элементов, входящих в состав API среды выполнения Windows на языке XAML, включая Windows::UI::Xaml и Windows::UI::Xaml::Controls. Код, обрабатывающий поведение элементов пользовательского интерфейса на языке XAML, определяется в файле кода программной части Main.xaml.cpp. Простые фигуры можно рисовать как прямоугольники и эллипсы.
Изменение размеров окон События изменения размеров и состояния представления обрабатываются естественным образом, и наложение трансформируется в соответствии с ними Необходимо вручную указывать, как будут перерисовываться компоненты наложения.

Другое существенное различие связано с цепочкой буферов. Цепочку буферов не нужно присоединять к объекту Windows::UI::Core::CoreWindow. Вместо этого приложение DirectX, в котором используется XAML, соединяется с цепочкой буферов при создании нового объекта SwapChainPanel.

В следующем фрагменте кода показано, как объявить разметку XAML для SwapChainPanel в файле DirectXPage.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 объекта текущего окна, создаваемого при запуске 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();
}

Чтобы привязать настроенную цепочку буферов к экземпляру SwapChainPanel, определенному разметкой XAML, необходимо получить указатель на базовую реализацию интерфейса ISwapChainPanelNative и вызвать для него метод ISwapChainPanelNative::SetSwapChain, передав ему настроенную цепочку буферов.

Следующий фрагмент из DX::D eviceResources::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 соответственно.