Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo argomento descrive le caratteristiche fondamentali del progetto Marble Maze, ad esempio come usa Visual C++ nell'ambiente Windows Runtime, come viene creato e strutturato e come viene compilato. L'argomento descrive anche diverse convenzioni usate nel codice.
Annotazioni
Il codice di esempio corrispondente a questo documento è disponibile nell'esempio di gioco DirectX Marble Maze .
Ecco alcuni dei punti chiave illustrati in questo documento per la pianificazione e lo sviluppo del gioco UWP (Universal Windows Platform).
- Usa il modello DirectX 11 App (Windows universale - C++/CX) in Visual Studio per creare il tuo gioco UWP DirectX.
- Windows Runtime fornisce classi e interfacce in modo da poter sviluppare app UWP in modo più moderno e orientato agli oggetti.
- Usa i riferimenti agli oggetti con il simbolo hat (^) per gestire il ciclo di vita delle variabili di Windows Runtime, Microsoft::WRL::ComPtr per gestire il ciclo di vita degli oggetti COM e std::shared_ptr o std::unique_ptr per gestire il ciclo di vita di tutti gli altri oggetti C++ allocati sull'heap.
- Nella maggior parte dei casi, usare la gestione delle eccezioni, anziché i codici dei risultati, per gestire gli errori imprevisti.
- Usare annotazioni SAL insieme agli strumenti di analisi del codice per individuare gli errori nell'app.
Creazione del progetto di Visual Studio
Se hai scaricato ed estratto l'esempio, puoi aprire il file MarbleMaze_VS2017.sln (nella cartella C++) in Visual Studio e avrai il codice davanti a te.
Quando abbiamo creato il progetto di Visual Studio per Marble Maze, abbiamo avviato un progetto esistente. Tuttavia, se non hai già un progetto esistente che fornisce la funzionalità di base richiesta dal tuo gioco UWP DirectX, ti consigliamo di creare un progetto basato sul modello App DirectX 11 di Visual Studio (Windows universale - C++/CX) perché fornisce un'applicazione 3D funzionante di base. Per fare questo, segui questi passaggi:
In Visual Studio 2019 selezionare File > Nuovo > progetto...
Nella finestra Crea un nuovo progetto, selezionare DirectX 11 App (Windows universale - C++/CX). Se questa opzione non viene visualizzata, è possibile che non siano installati i componenti necessari. Per informazioni su come installare componenti aggiuntivi, vedere Modificare Visual Studio 2019 aggiungendo o rimuovendo carichi di lavoro e componenti .
- Selezionare
Avanti e quindi immettere un nome di progetto, un percorso per i file da archiviare e un nome soluzione e quindi selezionareCrea .
Un'impostazione importante del progetto nel modello DirectX 11 App (Universale Windows - C++/CX) è l'opzione /ZW, che consente al programma di usare le estensioni del linguaggio di Windows Runtime. Questa opzione è abilitata per impostazione predefinita quando si usa il modello di Visual Studio. Per ulteriori informazioni su come impostare le opzioni del compilatore in Visual Studio, consultare le opzioni del compilatore e linker (C++/CX) ai riferimenti e.
Attenzione L'opzione /ZW non è compatibile con opzioni come /clr. Nel caso di /clr, ciò significa che non è possibile mirare sia il .NET Framework che il Windows Runtime dallo stesso progetto Visual C++.
Ogni app UWP acquisita da Microsoft Store è costituita da un pacchetto di app. Un pacchetto dell'app contiene un file manifesto del pacchetto, che contiene informazioni sulla tua app. Ad esempio, è possibile specificare le funzionalità (ovvero l'accesso necessario alle risorse di sistema protette o ai dati utente) dell'app. Se si determina che l'app richiede determinate funzionalità, usare il manifesto del pacchetto per dichiarare le funzionalità necessarie. Il manifesto consente anche di specificare le proprietà del progetto, ad esempio le rotazioni dei dispositivi supportate, le immagini di riquadri e la schermata iniziale. È possibile modificare il manifesto aprendo Package.appxmanifest nel progetto. Per altre informazioni sui pacchetti di app, vedi Creazione di pacchetti di app.
Creazione, distribuzione ed esecuzione del gioco
Nei menu a discesa nella parte superiore di Visual Studio selezionare la configurazione della distribuzione a sinistra del pulsante di riproduzione verde. È consigliabile impostare come Debug in modo che sia destinata all'architettura del dispositivo (x86 per 32 bit, x64 per 64 bit) e al computer locale . È anche possibile eseguire test su un computer remoto o su un dispositivo connesso tramite USB. Fare quindi clic sul pulsante verde "Play" per compilare e distribuire sul dispositivo.
Controllo del gioco
Puoi usare il tocco, l'accelerometro, un controller di gioco o il mouse per controllare Marble Maze.
- Usare il riquadro direzionale sul controller per modificare la voce di menu attiva.
- Usare il tocco, il pulsante A o Start sul controller o il mouse per selezionare una voce di menu.
- Usare il tocco, l'accelerometro, la levetta sinistra o il mouse per inclinare il labirinto.
- Usare il tocco, il pulsante A o Start sul controller o il mouse per chiudere i menu, ad esempio la tabella con punteggio elevato.
- Usa il pulsante Start sul controller o il tasto P sulla tastiera per sospendere o riprendere il gioco.
- Usa il pulsante Indietro sul controller o il tasto Home sulla tastiera per riavviare il gioco.
- Quando la tabella con punteggio elevato è visibile, usare il pulsante Indietro sul controller o il tasto Home sulla tastiera per cancellare tutti i punteggi.
Convenzioni del codice
Windows Runtime è un'interfaccia di programmazione che puoi usare per creare app UWP eseguite solo in un ambiente applicazione speciale. Tali app usano funzioni autorizzate, tipi di dati e dispositivi e vengono distribuite da Microsoft Store. Al livello più basso, Windows Runtime è costituito da un'interfaccia ABI (Application Binary Interface). L'interfaccia ABI è un contratto binario di basso livello che rende le API di Windows Runtime accessibili a più linguaggi di programmazione, ad esempio JavaScript, i linguaggi .NET e Visual C++.
Per chiamare le API di Windows Runtime da JavaScript e .NET, questi linguaggi necessitano di proiezioni specifiche per ciascun ambiente linguistico. Quando si chiama un'API di Windows Runtime da JavaScript o .NET, si esegue la proiezione, che a sua volta richiama la funzione ABI sottostante. Anche se è possibile chiamare le funzioni ABI direttamente in C++, Microsoft fornisce anche proiezioni per C++, perché rendono molto più semplice usare le API di Windows Runtime, mantenendo comunque prestazioni elevate. Microsoft fornisce anche estensioni del linguaggio per Visual C++ che supportano in modo specifico le proiezioni di Windows Runtime. Molte di queste estensioni del linguaggio sono simili alla sintassi per il linguaggio C++/CLI. Tuttavia, invece di impostare come destinazione Common Language Runtime (CLR), le app native usano questa sintassi per specificare come destinazione Windows Runtime. Il riferimento all'oggetto, o modificatore hat (^), è una parte importante di questa nuova sintassi perché consente la cancellazione automatica degli oggetti di runtime tramite il conteggio dei riferimenti. Anziché chiamare metodi come AddRef e Release per gestire la durata di un oggetto Windows Runtime, il runtime elimina l'oggetto quando non vi fa riferimento alcun altro componente, ad esempio quando esce dall'ambito o si impostano tutti i riferimenti a nullptr. Un'altra parte importante dell'uso di Visual C++ per creare app UWP è la parola chiave ref new . Usare ref new anziché new per creare oggetti Windows Runtime con conteggio dei riferimenti. Per altre info, vedi Type System (C++/CX).
Importante
È necessario usare ^ e ref new quando si creano oggetti Windows Runtime o si creano componenti Windows Runtime. È possibile usare la sintassi C++ standard quando si scrive codice dell'applicazione principale che non usa Windows Runtime.
Marble Maze usa ^ insieme a Microsoft::WRL::ComPtr per gestire gli oggetti allocati dall'heap e ridurre al minimo le perdite di memoria. È consigliabile usare ^ per gestire la durata delle variabili di Windows Runtime, ComPtr per gestire la durata delle variabili COM (ad esempio quando si usa DirectX) e std::shared_ptr o std::unique_ptr per gestire la durata di tutti gli altri oggetti C++ allocati dall'heap.
Per altre info sulle estensioni del linguaggio disponibili per un'app UWP C++, vedi Riferimenti al linguaggio Visual C++ (C++/CX).
Gestione degli errori
Marble Maze usa la gestione delle eccezioni come metodo principale per gestire gli errori imprevisti. Sebbene il codice del gioco usi tradizionalmente log o codici di errore, come i valori di HRESULT, per indicare errori, la gestione delle eccezioni presenta due vantaggi principali. In primo luogo, può semplificare la lettura e la manutenzione del codice. Dal punto di vista del codice, la gestione delle eccezioni è un modo più efficiente per propagare un errore a una routine in grado di gestire tale errore. L'uso dei codici di errore richiede in genere che ogni funzione propaga in modo esplicito gli errori. Un secondo vantaggio è che è possibile configurare il debugger di Visual Studio per interrompersi quando si verifica un'eccezione, in modo da poterti fermare immediatamente nel punto e nel contesto dell'errore. Windows Runtime usa anche ampiamente la gestione delle eccezioni. Pertanto, usando la gestione delle eccezioni nel codice, è possibile combinare tutta la gestione degli errori in un unico modello.
È consigliabile usare le convenzioni seguenti nel modello di gestione degli errori:
Usare le eccezioni per comunicare errori imprevisti.
Non usare eccezioni per controllare il flusso di codice.
Intercetta solo le eccezioni che puoi gestire e da cui puoi recuperare in modo sicuro. In caso contrario, non intercettare l'eccezione e lasciare che l'app si chiuda.
Quando si chiama una routine DirectX, che restituisce HRESULT, usa la funzione DX::ThrowIfFailed. Questa funzione è definita in DirectXHelper.h. ThrowIfFailed genera un'eccezione se il HRESULT fornito è un codice di errore. Ad esempio, E_POINTER fa sì che ThrowIfFailed generi Platform::NullReferenceException.
Quando si usa ThrowIfFailed, inserire la chiamata DirectX su una riga separata per migliorare la leggibilità del codice, come illustrato nell'esempio seguente.
// Identify the physical adapter (GPU or card) this device is running on. ComPtr<IDXGIAdapter> dxgiAdapter; DX::ThrowIfFailed( dxgiDevice->GetAdapter(&dxgiAdapter) );
Sebbene sia consigliabile evitare l'uso di HRESULT per errori imprevisti, è più importante evitare l'uso della gestione delle eccezioni per controllare il flusso di codice. Pertanto, è preferibile usare un valore restituito HRESULT quando necessario per controllare il flusso di codice.
Annotazioni SAL
Usare annotazioni SAL insieme agli strumenti di analisi del codice per individuare gli errori nell'app.
Usando il linguaggio di annotazione del codice sorgente Microsoft (SAL), è possibile annotare o descrivere il modo in cui una funzione usa i relativi parametri. Le annotazioni SAL descrivono anche i valori restituiti. Le annotazioni SAL funzionano con lo strumento di analisi del codice C/C++ per individuare i possibili difetti nel codice sorgente C e C++. Gli errori di codifica comuni segnalati dallo strumento includono overflow del buffer, memoria non inizializzata, dereferenziazioni di puntatori nulli e perdite di memoria e risorse.
Si consideri il metodo BasicLoader::LoadMesh, dichiarato in BasicLoader.h. Questo metodo usa _In_
per specificare che nome file è un parametro di input (e pertanto verrà letto solo), _Out_
per specificare che vertexBuffer e indexBuffer sono parametri di output (e pertanto verranno scritti solo) e _Out_opt_
per specificare che vertexCount e indexCount sono parametri di output facoltativi (e potrebbero essere scritti). Poiché vertexCount e indexCount sono parametri di output facoltativi, possono essere nullptr. Lo strumento di analisi del codice C/C++ esamina le chiamate a questo metodo per assicurarsi che i parametri passati soddisfino questi criteri.
void LoadMesh(
_In_ Platform::String^ filename,
_Out_ ID3D11Buffer** vertexBuffer,
_Out_ ID3D11Buffer** indexBuffer,
_Out_opt_ uint32* vertexCount,
_Out_opt_ uint32* indexCount
);
Per eseguire l'analisi del codice nell'app, nella barra dei menu scegliere Compila > Esegui analisi del codice nella soluzione. Per altre informazioni sull'analisi del codice, vedere Analisi della qualità del codice C/C++ tramite l'analisi del codice.
L'elenco completo delle annotazioni disponibili è definito in sal.h. Per ulteriori informazioni, vedere Annotazioni SAL .
Passaggi successivi
Leggi la struttura dell'applicazione Marble Maze per informazioni su come è strutturato il codice dell'applicazione Marble Maze e su come la struttura di un'app UWP DirectX differisca da quella di un'applicazione desktop tradizionale.
Argomenti correlati