Partager via


Notions de base de l’exemple Marble Maze

Cette rubrique présente les principales caractéristiques du projet Marble Maze, notamment la façon dont il utilise Visual C++ dans l’environnement Windows Runtime, mais également la façon dont il est créé, structuré et généré. La rubrique décrit également plusieurs conventions utilisées dans le code.

Remarque

L’échantillon de code qui correspond à ce document se trouve dans l’échantillon de jeu Marble Maze DirectX.

Voici quelques-uns des points clés abordés dans ce document, concernant la planification et le développement du jeu sur plateforme Windows universelle (UWP).

  • Utilisez le modèle de l’application DirectX 11 (Windows universel - C++/CX) dans Visual Studio pour créer votre jeu UWP DirectX.
  • Le Windows Runtime fournit des classes et des interfaces vous permettant de développer des applications UWP grâce à une approche plus moderne et orientée objet.
  • Utilisez des références d’objet comportant le symbole d’accent circonflexe (^) pour gérer la durée de vie des variables Windows Runtime, Microsoft::WRL::ComPtr pour gérer la durée de vie des objets COM et std::shared_ptr ou std::unique_ptr pour gérer la durée de vie de tous les autres objets C++ alloués par segment de mémoire.
  • Dans la majorité des cas, utilisez la gestion des exceptions plutôt que les codes de résultats pour gérer les erreurs inattendues.
  • Utilisez les annotations SAL et les outils d'analyse du code pour découvrir les erreurs présentes dans votre application.

Création du projet Visual Studio

Si vous avez téléchargé et extrait l’exemple, vous pouvez ouvrir le fichier MarbleMaze_VS2017.sln (dans le dossier C++) dans Visual Studio, et vous disposerez du code devant vous.

Nous sommes partis d'un projet existant pour la création du projet Visual Studio Marble Maze. Toutefois, si vous ne disposez pas déjà d’un projet offrant les fonctionnalités de base nécessaires à votre jeu pour UWP en DirectX, nous vous recommandons de créer un projet à partir du modèle Visual Studio Application DirectX 11 (Windows universel - C++/CX) qui fournit une application 3D avec les fonctionnalités de base en question. Pour ce faire, procédez comme suit :

  1. Dans Visual Studio 2019, sélectionnez Fichier > Nouveau > Projet...

  2. Dans la fenêtre Créer un projet, sélectionnez Application DirectX 11 (Windows universel - C++/CX). Si vous ne voyez pas cette option, vous n’avez peut-être pas installé les composants requis. Pour plus d’informations sur l’installation de composants supplémentaires, consultez Modifier Visual Studio 2019 en ajoutant ou en supprimant des charges de travail et des composants.

Nouveau projet

  1. Sélectionnez Suivant, puis entrez un nom de projet, un emplacement pour les fichiers à stocker et un nom de solution, puis sélectionnez Créer.

Un paramètre de projet important dans le modèle Application DirectX 11 (Windows universel - C++/CX) est l’option /ZW, qui permet au programme d’utiliser les extensions de langage Windows Runtime. Cette option est activée par défaut lorsque vous utilisez le modèle Visual Studio. Pour plus d’informations sur la définition des options du compilateur dans Visual Studio, consultez Options du compilateur et de l’éditeur de liens (C++/CX).

Attention L’option /ZW n’est pas compatible avec des options telles que /clr. Dans le cas de /clr, cela signifie que vous ne pouvez pas cibler à la fois le .NET Framework et le Windows Runtime à partir du même projet Visual C++.

 

Chaque application UWP que vous achetez à partir du Microsoft Store se présente sous la forme d’un package d’application. Un package d'application comprend un manifeste du package qui contient des informations au sujet de votre application. Par exemple, vous pouvez spécifier les capacités (autrement dit, l'accès requis aux ressources système ou aux données utilisateur protégées) de votre application. Si votre application nécessite certaines fonctionnalités, utilisez le manifeste du package pour les déclarer. Le manifeste vous permet également de spécifier des propriétés de projet telles que les rotations prises en charge de l'appareil, les images en mosaïque et l'écran de démarrage. Vous pouvez modifier le manifeste en ouvrant Package.appxmanifest dans votre projet. Pour plus d’informations sur les packages d’applications, consultez Empaquetage des applications.

Génération, déploiement et exécution du jeu

Dans les menus déroulants en haut de Visual Studio, à gauche du bouton de lecture vert, sélectionnez votre configuration de déploiement. Nous vous recommandons de le définir en tant que Débogage ciblant l’architecture de votre appareil (x86 pour 32 bits, x64 pour 64 bits) et sur votre ordinateur local. Vous pouvez également effectuer des tests sur un ordinateur distant ou sur un appareil connecté via USB. Cliquez ensuite sur le bouton de lecture vert pour générer et déployer sur votre appareil.

Déboguer; x64 ; Ordinateur local

Contrôle du jeu

Vous pouvez utiliser l’interaction tactile, l'accéléromètre, la manette Xbox 360 ou la souris comme contrôles du jeu Marble Maze.

  • Utilisez la croix directionnelle de la manette pour modifier l'élément de menu actif.
  • Utilisez l’interaction tactile, le bouton A ou Start sur la manette ou la souris pour sélectionner un élément de menu.
  • Utilisez l’interaction tactile, l'accéléromètre, le stick analogique gauche ou la souris pour incliner le jeu.
  • Utilisez l’interaction tactile, le bouton A ou Start sur la manette ou la souris pour fermer des menus tels que le tableau des meilleurs scores.
  • Utilisez le bouton Start de la manette ou la touche P du clavier pour suspendre ou reprendre le jeu.
  • Utilisez le bouton Précédent de la manette ou la touche Accueil du clavier pour redémarrer le jeu.
  • Lorsque le tableau des meilleurs scores est visible, utilisez le bouton Précédent sur la manette ou la touche Accueil du clavier pour effacer tous les scores.

Conventions de code

Le Windows Runtime est une interface de programmation permettant de créer des applications UWP qui ne peuvent être exécutées que dans un environnement d'application particulier. Ces applications utilisent des fonctionnalités, des types de données et des appareils autorisés, et sont distribuées par le biais du Microsoft Store. Au niveau le plus bas, le Windows Runtime est composé d'une interface binaire d'application (ABI). L'ABI est un contrat binaire de bas niveau qui rend les API Windows Runtime accessibles à plusieurs langages de programmation, tels que le JavaScript et les langages .NET et Visual C++.

Pour pouvoir appeler les API Windows Runtime, les langages JavaScript et .NET nécessitent des projections spécifiques à chaque environnement de langage. Lorsque vous appelez une API Windows Runtime à partir des langages JavaScript et .NET, vous appelez la projection, qui, à son tour, appelle la fonction ABI sous-jacente. Bien qu'il soit possible d'appeler les fonctions de l'interface binaire d'application directement depuis le code C++, Microsoft fournit également des projections pour le langage C++, qui facilitent l'utilisation des API Windows Runtime, tout en maintenant des performances élevées. Microsoft fournit également des extensions de langage Visual C++, conçues spécialement pour prendre en charge les projections Windows Runtime. Plusieurs de ces extensions de langage possèdent une syntaxe similaire à celle du langage C++/CLI. Toutefois, au lieu de cibler le Common Langage Runtime (CLR), les applications natives utilisent cette syntaxe pour cibler le Windows Runtime. Le modificateur de référence d'objet, ou accent circonflexe (^), est un élément important de cette nouvelle syntaxe, car il permet l'effacement automatique des objets d'exécution au moyen du décompte de références. Au lieu d'appeler des méthodes telles queAddRef et Release pour gérer la durée de vie d'un objet Windows Runtime, le runtime supprime l'objet lorsqu'aucun autre composant ne le référence, comme par exemple, lorsqu'il quitte la portée ou lorsque vous définissez toutes les références sur nullptr. Un autre aspect important de l'utilisation de Visual C++ pour la création d'applications UWP est l'utilisation du mot clé ref new. Utilisez ref new au lieu de nouveau pour créer des objets Windows Runtime avec comptage des références. Pour plus d’informations, consultez Type System (C++/CX).

Important

Vous devez uniquement utiliser ^ et ref new lorsque vous créez des objets Windows Runtime ou créez des composants Windows Runtime. Vous pouvez utiliser la syntaxe C++ standard lorsque vous écrivez le code d'une application de base qui n'utilise pas le Windows Runtime.

Le jeu Marble Maze utilise ^ et Microsoft::WRL::ComPtr pour gérer les objets alloués par tas et réduire les fuites de mémoire. Nous vous recommandons d’utiliser ^ pour gérer la durée de vie des variables Windows Runtime, ComPtr pour gérer la durée de vie des variables COM (par exemple, lorsque vous utilisez DirectX) et std ::shared_ptr ou std ::unique_ptr pour gérer la durée de vie de tous les autres objets C++ alloués par tas.

 

Pour plus d’informations sur les extensions de langage disponibles pour une application C++ UWP, consultez Référence du langage Visual C++ (C++/CX).

Gestion des erreurs

Le jeu Marble Maze utilise la gestion des exceptions comme principal moyen de gérer les erreurs inattendues. Même si le code des jeux utilise généralement des codes de journalisation ou des codes d'erreur, tels que les valeurs HRESULT, pour indiquer des erreurs, la gestion des exceptions présente deux principaux avantages. En premier lieu, elle facilite la lecture et la maintenance du code. Du point de vue du code, la gestion des exceptions constitue un moyen plus efficace de propager une erreur vers une routine qui se chargera de sa gestion. L'utilisation de codes d'erreur requiert généralement que chaque fonction propage explicitement les erreurs. L'autre avantage est que vous pouvez configurer le débogueur Visual Studio de façon à s'arrêter immédiatement au niveau de l'emplacement et du contexte de l'erreur lorsqu'une exception est levée. Windows Runtime utilise également largement la gestion des exceptions. Par conséquent, l'utilisation de la gestion des exceptions dans votre code permet de regrouper la gestion de toutes les erreurs en un seul et même modèle.

Il est recommandé d'utiliser les conventions suivantes dans votre modèle de gestion des erreurs :

  • Utilisez des exceptions pour communiquer des erreurs inattendues.

  • N'utilisez pas les exceptions pour contrôler le flux du code.

  • Interceptez uniquement les exceptions que vous pouvez gérer sans risque et à partir desquelles une récupération est possible. Sinon, n'interceptez pas l'exception et permettez à l'exécution de l'application de se terminer.

  • Lorsque vous appelez une routine DirectX qui retourne HRESULT, utilisez la fonction DX ::ThrowIfFailed. Cette fonction est définie dans DirectXHelper.h. ThrowIfFailed lève une exception si le HRESULT fourni est un code d’erreur. Par exemple, E\_POINTER provoque la levée de Platform::NullReferenceException par ThrowIfFailed.

    Lorsque vous utilisez ThrowIfFailed, placez l'appel DirectX sur une ligne distincte pour améliorer la lisibilité du code, comme dans l'exemple suivant.

    // Identify the physical adapter (GPU or card) this device is running on.
    ComPtr<IDXGIAdapter> dxgiAdapter;
    DX::ThrowIfFailed(
        dxgiDevice->GetAdapter(&dxgiAdapter)
        );
    
  • Même si l’utilisation de HRESULT pour les erreurs inattendues est à éviter, il est encore plus important d’éviter celle de la gestion des exceptions pour contrôler le flux de code. Par conséquent, il est préférable d'utiliser une valeur de retour HRESULT, si nécessaire, pour contrôler le flux du code.

Annotations SAL

Utilisez les annotations SAL et les outils d'analyse du code pour découvrir les erreurs présentes dans votre application.

Le langage SAL de Microsoft vous permet d’annoter (ou décrire) la façon dont une fonction utilise ses paramètres. Les annotations SAL permettent également de décrire des valeurs de retour. Les annotations SAL peuvent être utilisées conjointement à l'outil d'analyse du code C/C++ pour découvrir les éventuelles erreurs du code source C ou C++. Les erreurs de codage courantes signalées par l'outil sont notamment les dépassements de mémoire tampon, une mémoire non initialisée, les déréférencements du pointeur Null et les fuites de mémoire et de ressources.

Utilisez plutôt la méthode BasicLoader::LoadMesh qui est déclarée dans BasicLoader.h. Cette méthode utilise _In_ pour spécifier que filename est un paramètre d’entrée (et ne peut donc faire que l’objet d’une lecture), _Out_ pour spécifier que vertexBuffer et indexBuffer sont des paramètres de sortie (et ne feront donc que l’objet d’une écriture), et _Out_opt_ pour spécifier que vertexCount et indexCount sont des paramètres de sortie facultatifs (pouvant faire l’objet d’une écriture). Étant donné que vertexCount et indexCount sont des paramètres de sortie facultatifs, ils sont autorisés à être nullptr. L'outil d'analyse du code C/C++ examine les appels à cette méthode pour s'assurer que les paramètres qu'elle transmet répondent à ces critères.

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

Pour effectuer l'analyse du code de votre application, dans la barre de menus, sélectionnez Générer > Exécuter l'analyse du code sur la solution. Pour plus d’informations sur l’analyse du code, consultez Analyse de la qualité du code C/C++ à l’aide de l’analyse du code.

La liste complète des annotations disponibles est définie dans le fichier sal.h. Pour plus d'informations, consultez Annotations SAL.

Étapes suivantes

Consultez Structure de l’application Marble Maze pour plus d'informations sur la façon dont le code de l'application Marble Maze est structuré, ainsi que sur les différences entre la structure d'une application UWP DirectX et celle d'une application de bureau traditionnelle.