Extender el juego de ejemplo

Nota:

Este tema forma parte de la serie de tutoriales Crear un juego de Plataforma universal de Windows simple (UWP) con DirectX. El tema de ese vínculo establece el contexto de la serie.

Para descargar la versión de este juego que usa XAML para la superposición, consulta Ejemplo de juego DirectX y XAML. Asegúrese de leer el archivo Léame allí para obtener más información sobre cómo compilar el ejemplo.

En este punto hemos tratado los componentes clave de un juego directX 3D de Plataforma universal de Windows básico (UWP). Puedes configurar el marco para un juego, incluido el proveedor de vistas y la canalización de representación, e implementar un bucle de juego básico. También puede crear una superposición básica de la interfaz de usuario, incorporar sonidos e implementar controles. Estás en camino para crear un juego propio, pero si necesitas más ayuda e información, echa un vistazo a estos recursos.

Uso de XAML para la superposición

Una alternativa que no analizamos en profundidad es el uso de XAML en lugar de Direct2D para la superposición. XAML tiene muchas ventajas sobre Direct2D para dibujar elementos de la interfaz de usuario. La ventaja más importante es que hace que la incorporación de la apariencia de Windows 10 en tu juego DirectX sea más cómoda. Muchos de los elementos, estilos y comportamientos comunes que definen a una aplicación para UWP están estrechamente integrados en el modelo XAML, por lo que implementarlos supone mucho menos trabajo para el desarrollador del juego. Si tu diseño de juego tiene una interfaz de usuario complicada, piensa en la posibilidad de usar XAML en lugar de Direct2D.

Con XAML, podemos crear una interfaz de juego similar a la direct2D realizada anteriormente.

XAML

Superposición xaml

Direct2D

Superposición D2D

Aunque tienen resultados finales similares, hay varias diferencias entre la implementación de interfaces Direct2D y XAML.

Característica XAML Direct2D
Definición de la superposición Definido en un archivo XAML, \*.xaml. Una vez que se entiende XAML, la creación y configuración de superposiciones más complicadas se convierten en simpiler en comparación con Direct2D. Se define como una colección de primitivos de Direct2D y DirectWrite cadenas colocadas y escritas manualmente en un búfer de destino de Direct2D.
Elementos de la interfaz de usuario Los elementos de la interfaz de usuario XAML proceden de elementos estandarizados que forman parte de las API XAML de Windows Runtime, incluidos Windows::UI::Xaml y Windows::UI::Xaml::Controls. El código que controla el comportamiento de los elementos de interfaz de usuario XAML se define en un archivo de código subyacente: Main.xaml.cpp. Las formas simples se pueden dibujar como rectángulos y puntos suspensivos.
Cambio de tamaño de ventana Controla de forma natural los eventos de cambio de estado de cambio de tamaño y visualización, transformando la superposición en consecuencia. Es necesario especificar manualmente cómo volver a dibujar los componentes de la superposición.

Otra gran diferencia implica la cadena de intercambio. No es necesario asociar la cadena de intercambio a un objeto Windows::UI::Core::CoreWindow . En su lugar, una aplicación DirectX que incorpora XAML asocia una cadena de intercambio cuando se construye un nuevo objeto SwapChainPanel .

En el fragmento de código siguiente se muestra cómo declarar XAML para SwapChainPanel en el archivo 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>

El objeto SwapChainPanel se establece como la propiedad Content del objeto de ventana actual creado al iniciar por el singleton de la aplicación.

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();
}

Para adjuntar la cadena de intercambio configurada a la instancia swapChainPanel definida por el XAML, debes obtener un puntero a la implementación de la interfaz ISwapChainPanelNative nativa subyacente y llamar a ISwapChainPanelNative::SetSwapChain en ella, pasándola la cadena de intercambio configurada.

El siguiente fragmento de código de DX::D eviceResources::CreateWindowSizeDependentResources detalla esto para la interoperabilidad de 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)
            );
    }

Para obtener más información sobre este proceso, consulta el tema sobre interoperación entre DirectX y XAML.

Ejemplo

Para descargar la versión de este juego que usa XAML para la superposición, consulta Ejemplo de juego DirectX y XAML. Asegúrese de leer el archivo Léame allí para obtener más información sobre cómo compilar el ejemplo.

A diferencia de la versión del juego de ejemplo que se describe en el resto de estos temas, la versión XAML define su marco en los archivos App.xaml.cpp y DirectXPage.xaml.cpp , en lugar de App.cpp y GameInfoOverlay.cpp, respectivamente.