Compartir a través de


Conceptos básicos sobre la muestra de Marble Maze

En este tema, se describen las características fundamentales del proyecto Marble Maze, por ejemplo, cómo usa Visual C++ en el entorno de Windows Runtime, cómo se crea y estructura, y cómo se compila. En el tema, también se describen varias de las convenciones que se usan en el código.

Nota:

El código de ejemplo que corresponde a este documento se encuentra en el ejemplo de juego Marble Maze de DirectX.

Estos son algunos de los puntos clave que describe este documento para cuando se realice la planeación y desarrollo del juego para la Plataforma universal de Windows (UWP).

  • Usa la plantilla Aplicación DirectX 11 (Universal Windows - C++/CX) en Visual Studio para crear el juego para UWP en DirectX.
  • Windows Runtime proporciona clases e interfaces para que pueda desarrollar aplicaciones para UWP de forma más moderna y orientada a objetos.
  • Use referencias de objeto con el símbolo de acento circunflejo (^) para administrar la duración de las variables de Windows Runtime, Microsoft::WRL::ComPtr para administrar la duración de los objetos COM y std::shared_ptr o std::unique_ptr para administrar la duración de todos los demás objetos C++ asignados al montón.
  • En la mayoría de los casos, use el control de excepciones en lugar de códigos de resultado para tratar los errores inesperados.
  • Use anotaciones de SAL junto con las herramientas de análisis de código para ayudar a detectar errores en la aplicación.

Creación del proyecto de Visual Studio

Si ha descargado y extraído el ejemplo, puede abrir el archivo MarbleMaze_VS2017.sln (en la carpeta C++) de Visual Studio. Ahí podrá ver el código.

Cuando creamos el proyecto de Visual Studio para Marble Maze, empezamos con un proyecto existente. Sin embargo, si aún no tiene un proyecto existente que proporcione la funcionalidad básica que requiere el juego para UWP en DirectX, le recomendamos que cree un proyecto basado en la plantilla Aplicación DirectX 11 (Universal Windows - C++/CX) de Visual Studio, ya que proporciona una aplicación 3D de trabajo básica. Para ello, siga estos pasos:

  1. En Visual Studio2019, seleccione Archivo> Nuevo > Proyecto...

  2. En la ventana Crear un nuevo proyecto, seleccione Aplicación DirectX 11 (Universal Windows - C++/CX). Si no ve esta opción, es posible que no tenga instalados los componentes necesarios. Consulte Modificación de Visual Studio 2019 mediante la adición y eliminación de cargas de trabajo y componentes para obtener información sobre cómo instalar más componentes.

Nuevo proyecto

  1. Seleccione Siguiente y, a continuación, escriba un Nombre de proyecto, una Ubicación en la que se almacenarán los archivos y un Nombre de solución. A continuación, seleccione Crear.

Una configuración importante del proyecto en la plantilla Aplicación DirectX 11 (Universal Windows - C++/CX) es la opción /ZW, que permite al programa usar las extensiones de lenguaje de Windows Runtime. Esta opción se habilita de forma predeterminada cuando usa la plantilla de Visual Studio. Consulte Opciones del compilador y del enlazador (C++/CX) para obtener más información sobre cómo establecer opciones del compilador en Visual Studio.

Precaución La opción /ZW no es compatible con opciones como /clr . En el caso de /clr, esto significa que no puede tener como destino .NET Framework y Windows Runtime desde el mismo proyecto de Visual C++.

 

Cada aplicación para UWP que adquiera de Microsoft Store tiene la forma de paquete de la aplicación. Un paquete de la aplicación contiene un manifiesto del paquete, que contiene información sobre la aplicación. Por ejemplo, puede especificar las capacidades (es decir, el acceso necesario a los recursos del sistema protegidos o a los datos de usuario) de la aplicación. Si determina que la aplicación necesita algunas capacidades, use el manifiesto del paquete para declarar las capacidades necesarias. El manifiesto también le permite especificar propiedades del proyecto como las rotaciones del dispositivo, las imágenes de mosaico y la pantalla de presentación que se admiten. Para editar el manifiesto, abra Package.appxmanifest en el proyecto. Para obtener más información sobre los paquetes de aplicaciones, consulte Empaquetado de aplicaciones.

Compilar, implementar y ejecutar el juego

En los menús desplegables de la parte superior de Visual Studio, a la izquierda del botón de reproducción verde, seleccione la configuración de implementación. Se recomienda establecer esto como Depuración, que tenga como destino la arquitectura del dispositivo (x86 para 32 bits, x64 para 64 bits) y en la máquina local. También puede probar en una máquina remota o en un dispositivo conectado a través de USB. A continuación, haga clic en el botón de reproducción verde para compilar e implementar en el dispositivo.

Depurar; x64; Equipo local

Controlar el juego

Puede usar un toque, el acelerómetro, un dispositivo de juego o el mouse para controlar Marble Maze.

  • Use el DPad del mando para cambiar el elemento de menú activo.
  • Use la función táctil, el botón A o Inicio del mando, o el mouse para seleccionar un elemento de menú.
  • Use un toque, el acelerómetro, la tecla de navegación izquierda o el mouse para inclinar el laberinto.
  • Use la función táctil, el botón A o Inicio del mando o el mouse para cerrar menús, como la tabla de puntuación alta.
  • Usa el botón Iniciar del mando o la tecla P del teclado para pausar o reanudar el juego.
  • Use el botón Atrás del mando o la tecla Inicio del teclado para reiniciar el juego.
  • Cuando la tabla de puntuación alta esté visible, use el botón Atrás del controlador o la tecla Inicio del teclado para borrar todas las puntuaciones.

Convenciones de código

Windows Runtime es una interfaz de programación que puedes usar para crear aplicaciones para UWP que solo se ejecutan en un entorno de aplicación especial. Esas aplicaciones usan funciones, tipos de datos y dispositivos autorizados, y se distribuyen desde la tienda Microsoft Store. En el nivel más bajo, Windows Runtime consta de una interfaz binaria de aplicaciones (ABI). La ABI es un contrato binario de bajo nivel que crea API de Windows Runtime accesibles para diversos lenguajes de programación como JavaScript, los lenguajes de .NET y Visual C++.

Para llamar a las API de Windows Runtime desde JavaScript y .NET, esos lenguajes necesitan proyecciones que son específicas de cada entorno de lenguaje. Cuando llama a una API de Windows Runtime desde JavaScript o .NET, está invocando la proyección, que a su vez llama a la función de ABI subyacente. Aunque puede llamar a las funciones de ABI directamente en C++, Microsoft proporciona también proyecciones para C++, porque simplifican mucho el uso de las API de Windows Runtime y siguen manteniendo un alto rendimiento. Microsoft también proporciona extensiones de lenguaje en Visual C++ que admiten específicamente las proyecciones de Windows Runtime. Muchas de estas extensiones de lenguaje se asemejan a la sintaxis del lenguaje C++/CLI. Sin embargo, en lugar de tener como destino Common Language Runtime (CLR), las aplicaciones nativas usan esta sintaxis para establecer como destino Windows Runtime. El modificador de referencia de objeto, o sombrero (^), es una parte importante de esta nueva sintaxis porque permite la eliminación automática de objetos de tiempo de ejecución mediante el recuento de referencias. En lugar de llamar a métodos como AddRef y Release para administrar la vigencia de un objeto de Windows Runtime, el runtime elimina el objeto cuando ningún otro componente hace referencia a él, por ejemplo cuando sale del ámbito o cuando se establecen todas las referencias en nullptr. Otra parte importante del uso de Visual C++ para crear aplicaciones para UWP es la palabra clave ref new. Use ref new en lugar de new para crear objetos de Windows Runtime con recuento de referencias. Para más información, consulte Type System (C++/CX).

Importante

Solo debe usar ^ y ref new al crear objetos o componentes de Windows Runtime. Puede usar la sintaxis de C++ estándar cuando escriba código básico de aplicaciones que no use Windows Runtime.

Marble Maze usa ^ junto con Microsoft::WRL::ComPtr para administrar objetos asignados por montón y minimizar las pérdidas de memoria. Se recomienda usar ^ para administrar la duración de las variables de Windows Runtime, ComPtr para administrar la duración de las variables COM (por ejemplo, cuando usa DirectX) y std::shared_ptr o std::unique_ptr para administrar la duración de todos los demás objetos C++ asignados al montón.

 

Para obtener más información sobre las extensiones de lenguaje que están disponibles para una aplicación para UWP de C++, consulte Referencia del lenguaje Visual C++ (C++/CX).

Control de errores

Marble Maze usa el control de excepciones como medio principal de abordar los errores inesperados. Aunque el código de los juegos usa tradicionalmente registro o códigos de error, como los valores HRESULT, para indicar errores, el control de excepciones presenta dos ventajas principales. En primer lugar, puede simplificar la lectura y el mantenimiento del código. Desde la perspectiva del código, el control de excepciones es una manera más eficaz de propagar un error a una rutina que pueda controlar dicho error. El uso de códigos de error suele necesitar que cada función propague explícitamente los errores. Una segunda ventaja es que puede configurar el depurador de Visual Studio para que se interrumpa cuando se produzca una excepción, de forma que pueda detenerse inmediatamente en la ubicación y el contexto del error. Windows Runtime también usa el control de excepciones ampliamente. Por tanto, si usa el control de excepciones en su código, puede agrupar todo el control de errores en un modelo.

Se recomienda que use las convenciones siguientes en su modelo de control de errores:

  • Use excepciones para notificar errores inesperados.

  • No use excepciones para controlar el flujo de código.

  • Capture solo las excepciones que pueda administrar y recuperar de forma segura. De lo contrario, no capture la excepción y permita que la aplicación finalice.

  • Cuando se llama a una rutina de DirectX que devuelve HRESULT, use la función DX::ThrowIfFailed. Esta función se define en DirectXHelper.h. ThrowIfFailed produce una excepción si el HRESULT proporcionado es un código de error. Por ejemplo, E\_POINTER hace que ThrowIfFailed inicie Platform::NullReferenceException.

    Cuando use ThrowIfFailed, coloque la llamada de DirectX en una línea diferente para ayudar a mejorar la legibilidad del código, como se muestra en el ejemplo siguiente.

    // Identify the physical adapter (GPU or card) this device is running on.
    ComPtr<IDXGIAdapter> dxgiAdapter;
    DX::ThrowIfFailed(
        dxgiDevice->GetAdapter(&dxgiAdapter)
        );
    
  • Aunque recomendamos que evite el uso de HRESULT para los errores inesperados, es más importante evitar el uso del controlador de excepciones para controlar el flujo de código. Por tanto, es preferible usar un valor devuelto de HRESULT cuando sea necesario controlar el flujo de código.

Anotaciones SAL

Usa anotaciones de SAL junto con las herramientas de análisis de código para ayudar a detectar errores en la aplicación.

Mediante el lenguaje de anotación de código fuente (SAL) de Microsoft, puede anotar, o describir, cómo una función usa sus parámetros. Las anotaciones de SAL también describen valores devueltos. Las anotaciones de SAL funcionan con la herramienta de análisis de código de C/C++ para detectar posibles defectos en el código fuente de C y C++. Entre los errores de codificación más frecuentes notificados por esta herramienta se incluyen saturaciones de búfer, memoria sin inicializar, desreferencias de puntero NULL, y pérdidas de memoria y recursos.

Considere el método BasicLoader::LoadMesh, que se declara en BasicLoader.h. Este método usa _In_ para especificar que filename es un parámetro de entrada (y, por tanto, solo se podrá leer), _Out_ para especificar que vertexBuffer e indexBuffer son parámetros de salida (y, por tanto, solo se escribirá en ellos) y _Out_opt_ para especificar que vertexCount e indexCount son parámetros de salida opcionales (y se puede escribir en ellos). Dado que vertexCount e indexCount son parámetros de salida opcionales, se les permite ser nullptr. La herramienta de análisis de código de C/C++ examina las llamadas a este método para asegurarse de que los parámetros que pasa cumplen estos criterios.

void LoadMesh(
    _In_ Platform::String^ filename,
    _Out_ ID3D11Buffer** vertexBuffer,
    _Out_ ID3D11Buffer** indexBuffer,
    _Out_opt_ uint32* vertexCount,
    _Out_opt_ uint32* indexCount
    );

Para realizar el análisis de código de la aplicación, en la barra de menús, elija Compilar > Ejecutar análisis de código en la solución. Para obtener más información sobre el análisis de código, vea Analizar la calidad de código de C/C++ mediante el análisis de código.

La lista completa de anotaciones disponibles se define en sal.h. Para obtener más información, consulte Anotaciones SAL.

Pasos siguientes

Lea Estructura de la aplicación Marble Maze para obtener información sobre cómo se estructura el código de la aplicación Marble Maze y cómo la estructura de una aplicación para UWP en DirectX difiere de la de una aplicación de escritorio tradicional.