Grundlagen am Beispiel von Marble Maze
In diesem Thema werden die grundlegenden Merkmale des Marble Maze-Projekts beschrieben, z. B. wie Visual C++ in der Windows-Runtime-Umgebung verwendet wird, wie es erstellt und strukturiert wird und wie es aufgebaut ist. Im Thema werden auch einige der Konventionen beschrieben, die im Code verwendet werden.
Hinweis
Den diesem Dokument entsprechenden Beispielcode finden Sie im DirectX-Beispiel anhand des Spiels Marble Maze.
Hier sind einige der wichtigsten Punkte, die in diesem Dokument erläutert werden, wenn Sie Ihr UWP-Spiel (Universelle Windows-Plattform) planen und entwickeln.
- Verwenden Sie die DirectX 11-App-Vorlage (Universelle Windows - C++/CX) in Visual Studio, um Ihr DirectX-UWP-Spiel zu erstellen.
- Windows-Runtime stellt Klassen und Schnittstellen bereit, damit Sie UWP-Apps auf modernere, objektorientierte Weise entwickeln können.
- Verwenden Sie Objektverweise mit dem Hutsymbol (^), um die Lebensdauer von Windows-Runtime-Variablen zu verwalten, Microsoft::WRL::ComPtr zum Verwalten der Lebensdauer von COM-Objekten und std::shared_ptr oder std::unique_ptr zum Verwalten der Lebensdauer aller anderen heap-zugeordneten C++-Objekte.
- In den meisten Fällen sollte die Ausnahmebehandlung anstelle von Ergebniscodes zur Behandlung unerwarteter Fehler verwendet werden.
- Verwenden Sie SAL-Anmerkungen zusammen mit Codeanalysetools, um Fehler in Ihrer App zu erkennen.
Erstellen des Visual Studio-Projekts
Wenn Sie das Beispiel heruntergeladen und extrahiert haben, können Sie die Datei MarbleMaze_VS2017.sln (im C++ -Ordner) in Visual Studio öffnen, und Sie haben den Code vor sich.
Bei der Erstellung des Visual Studio-Projekts für Marble Maze haben wir ein vorhandenes Projekt als Grundlage verwendet. Wenn Sie jedoch noch nicht über ein vorhandenes Projekt verfügen, das die grundlegenden Funktionen bereitstellt, die Ihr DirectX-UWP-Spiel erfordert, empfehlen wir, ein Projekt basierend auf der Visual Studio DirectX 11-App-Vorlage (Universal Windows - C++/CX) zu erstellen, da sie eine einfache 3D-Anwendung bereitstellt. Gehen Sie dazu wie folgt vor:
Wählen Sie in Visual Studio 2019 Datei > Neu > Projekt... aus
Wählen Sie im Fenster Neues Projekt erstellen die Option DirectX 11-App (Universelle Windows - C++/CX) aus. Wenn diese Option nicht angezeigt wird, sind möglicherweise nicht die erforderlichen Komponenten installiert. Weitere Informationen zum Installieren zusätzlicher Komponenten finden Sie unter Ändern von Visual Studio 2019, indem Sie Arbeitslasten und Komponenten hinzufügen oder entfernen.
- Wählen Sie Weiteraus, und geben Sie dann einen Projektnamen, einen Speicherort für die zu speichernden Dateien, und einen Projektmappennamenein, und wählen Sie dann Erstellen aus.
Eine wichtige Projekteinstellung in der DirectX 11-App-Vorlage (Universelle Windows - C++/CX) ist die Option /ZW, mit der das Programm die Windows-Runtime-Spracherweiterungen verwenden kann. Diese Option ist standardmäßig aktiviert, wenn Sie die Visual Studio-Vorlage verwenden. Weitere Informationen zum Festlegen von Compileroptionen in Visual Studio finden Sie unter Compiler- und Linkeroptionen (C++/CX).
Achtung, die /ZW-Option ist nicht mit Optionen wie /clr kompatibel. Im Fall von /clr bedeutet dies, dass Sie sowohl das .NET Framework als auch die Windows-Runtime nicht aus demselben Visual C++-Projekt als Ziel verwenden können.
Jede UWP-App, die Sie aus dem Microsoft Store erwerben, wird in Form eines App-Pakets bereitgestellt. Ein App-Paket enthält ein Paketmanifest, das Informationen über die App bereitstellt. Beispielsweise können Sie die Funktionen der App angeben (also den erforderlichen Zugriff auf geschützte Systemressourcen oder Benutzerdaten). Wenn Sie festlegen, dass die App bestimmte Funktionen erfordert, deklarieren Sie die erforderlichen Funktionen im Paketmanifest. Im Manifest können Sie auch Projekteigenschaften festlegen, z. B. unterstützte Gerätedrehungen, Kachelbilder und den Begrüßungsbildschirm. Sie können das Manifest bearbeiten, indem Sie Package.appxmanifest in Ihrem Projekt öffnen. Weitere Informationen zu App-Paketen finden Sie unter Verpacken von Apps.
Erstellen, Bereitstellen und Ausführen des Spiels
Wählen Sie in den Dropdownmenüs oben in Visual Studio links neben der grünen Wiedergabeschaltfläche Ihre Bereitstellungskonfiguration aus. Es wird empfohlen, sie als Debug-Ziel für die Architektur Ihres Geräts (x86 für 32-Bit, x64 für 64-Bit) und auf Ihren lokalen Computer festzulegen. Sie können auch auf einem Remotecomputer oder auf einem Gerät testen, das über USB verbunden ist. Klicken Sie dann auf die grüne Wiedergabeschaltfläche, um ihr Gerät zu erstellen und bereitzustellen.
Steuern des Spiels
Sie können Toucheingabe, Beschleunigungsmesser, einen Gamecontroller oder die Maus verwenden, um Marble Maze zu steuern.
- Verwenden Sie das Steuerkreuz des Controllers, um das aktive Menüelement zu ändern.
- Verwenden Sie die Toucheingabe, die A- oder Starttaste auf dem Controller oder die Maus, um ein Menüelement zu wählen.
- Verwenden Sie die Fingereingabe, den Beschleunigungsmesser, den linken Ministick oder die Maus, um das Labyrinth zu kippen.
- Verwenden Sie die Toucheingabe, die A- oder Starttaste auf dem Controller oder die Maus, um Menüs wie die Highscore-Tabelle zu schließen.
- Verwenden Sie die Starttaste auf dem Controller oder die P-Taste auf der Tastatur, um das Spiel anzuhalten oder fortzusetzen.
- Verwenden Sie die Zurück-Taste auf dem Controller oder die Start-Taste auf der Tastatur, um das Spiel neu zu starten.
- Wenn die Highscore-Tabelle sichtbar ist, verwenden Sie die Zurück-Taste auf dem Controller oder die Start-Taste auf der Tastatur, um alle Bewertungen zu löschen.
Codekonventionen
Windows-Runtime ist eine Programmierschnittstelle, mit der Sie UWP-Apps erstellen können, die nur in einer speziellen Anwendungsumgebung ausgeführt werden können. Solche Apps verwenden autorisierte Funktionen, Datentypen und Geräte, und sie werden über den Microsoft Store verteilt. Auf der niedrigsten Ebene besteht die Windows-Runtime aus einem Application Binary Interface (ABI). Die ABI ist ein binärer Vertrag auf niedriger Ebene, der Windows-Runtime-APIs für mehrere Programmiersprachen wie JavaScript, .NET-Sprachen und Visual C++ zugänglich macht.
Um Windows-Runtime-APIs aus JavaScript und .NET aufzurufen, benötigen diese Sprachen Projektionen, die für jede Sprachumgebung spezifisch sind. Wenn Sie eine Windows-Runtime-API aus JavaScript oder .NET aufrufen, rufen Sie die Projektion auf, die wiederum die zugrunde liegende ABI-Funktion aufruft. Obwohl Sie die ABI-Funktionen direkt in C++ aufrufen können, stellt Microsoft auch Projektionen für C++ bereit, da sie die Verwendung der Windows-Runtime-APIs erheblich vereinfachen und gleichzeitig eine hohe Leistung gewährleisten. Microsoft stellt auch Spracherweiterungen für Visual C++ bereit, die speziell die Windows-Runtime-Projektionen unterstützen. Viele dieser Spracherweiterungen ähneln dem Syntax für die Sprache C++-/CLI. Anstelle der Common Language Runtime (CLR) verwenden systemeigene Apps diese Syntax jedoch für die Windows-Runtime. Der Objektverweismodifizierer oder Dachmodifizierer (^) stellt einen wichtigen Bestandteil dieser neuen Syntax dar, da er das automatische Löschen von Laufzeitobjekten anhand der Verweiszählung ermöglicht. Anstatt Methoden wie AddRef und Release aufzurufen, um die Lebensdauer eines Windows-Runtime-Objekts zu verwalten, löscht die Laufzeit das Objekt, wenn keine andere Komponente darauf verweist, z. B. wenn sie den Bereich verlässt oder Sie alle Verweise auf nullptrfestlegen. Ein weiterer wichtiger Bestandteil der Verwendung von Visual C++ zum Erstellen von UWP-Apps ist das ref new-Schlüsselwort. Verwenden Sie refs new anstelle von new, um referenzgezählte Windows-Runtime-Objekte zu erstellen. Weitere Informationen finden Sie unter Type System (C++/CX).
Wichtig
Sie müssen beim Erstellen von Windows-Runtime-Objekten oder beim Erstellen von Komponenten für Windows-Runtime nur ^ und ref new verwenden. Sie können die C++-Standardsyntax verwenden, wenn Sie Kernanwendungscode schreiben, der Windows-Runtime nicht verwendet.
Marble Maze verwendet ^ zusammen mit Microsoft::WRL::ComPtr, um vom Heap zugewiesene Objekte zu verwalten und Speicherverluste zu minimieren. Es wird empfohlen, ^ zum Verwalten der Lebensdauer von Windows-Runtime-Variablen zu verwenden, ComPtr zum Verwalten der Lebensdauer von COM-Variablen (z. B. bei Verwendung von DirectX) und std::shared_ptr oder std::unique_ptr zum Verwalten der Lebensdauer aller anderen heap-zugeordneten C++-Objekte.
Weitere Informationen zu den Spracherweiterungen, die für eine C++-UWP-App verfügbar sind, finden Sie unter Visual C++-Sprachreferenz (C++/CX).
Fehlerbehandlung
Marble Maze verwendet hauptsächlich die Ausnahmebehandlung, um unerwartete Fehler zu behandeln. Obwohl Code für Spiele traditionell Protokollierungs- oder Fehlercodes verwendet, z. B. HRESULT-Werte, um Fehler anzuzeigen, hat die Ausnahmebehandlung zwei Hauptvorteile. Zum einen kann der Code dadurch besser lesbar und einfacher zu verwalten sein. Für den Code ist die Ausnahmebehandlung eine effizientere Möglichkeit, einen Fehler an eine Routine weiterzugeben, die diesen Fehler behandeln kann. Bei der Verwendung von Fehlercodes muss in der Regel jede Funktion Fehler explizit weitergeben. Ein zweiter Vorteil ist, dass Sie den Visual Studio-Debugger so konfigurieren können, dass er einen Vorgang unterbricht, sobald eine Ausnahme auftritt. So können Sie sofort an der Fehlerposition und im Fehlerkontext anhalten. Die Windows-Runtime verwendet auch eine umfangreiche Ausnahmebehandlung. Wenn Sie die Ausnahmebehandlung im Code verwenden, können Sie daher die gesamte Fehlerbehandlung in einem Modell zusammenfassen.
Es wird empfohlen, im Fehlerbehandlungsmodell die folgenden Konventionen zu verwenden:
Verwenden Sie Ausnahmen, um unerwartete Fehler zu übermitteln.
Verwenden Sie Ausnahmen nicht, um den Ablauf des Codes zu steuern.
Fangen Sie nur die Ausnahmen ab, die Sie auf sichere Weise behandeln und beheben können. Fangen Sie andere Ausnahmen nicht ab, sondern lassen Sie das Beenden der App zu.
Wenn Sie eine DirectX-Routine aufrufen, die HRESULT zurückgibt, verwenden Sie die Funktion DX::ThrowIfFailed. Diese Funktion wird in DirectXHelper.h definiert. ThrowIfFailed löst eine Ausnahme aus, wenn das bereitgestellte HRESULT ein Fehlercode ist. E\_POINTER bewirkt beispielsweise, dass ThrowIfFailed Platform::NullReferenceException auslöst.
Wenn Sie ThrowIfFailed verwenden, platzieren Sie den DirectX-Aufruf in einer separaten Zeile, um die Lesbarkeit von Code zu verbessern, wie im folgenden Beispiel gezeigt.
// Identify the physical adapter (GPU or card) this device is running on. ComPtr<IDXGIAdapter> dxgiAdapter; DX::ThrowIfFailed( dxgiDevice->GetAdapter(&dxgiAdapter) );
Obwohl empfohlen wird, die Verwendung von HRESULT für unerwartete Fehler zu vermeiden, ist es wichtiger, auf die Nutzung der Ausnahmebehandlung zur Steuerung des Codeflusses zu verzichten. Daher wird es bevorzugt, einen HRESULT-Rückgabewert zu verwenden, wenn erforderlich, um den Codefluss zu steuern.
SAL-Anmerkungen
Verwenden Sie SAL-Anmerkungen in Verbindung mit den Codeanalysetools, um Fehler in der App zu ermitteln.
Mit der Source Code Annotation Language von Microsoft (SAL) können Sie kommentieren oder beschreiben, wie eine Funktion ihre Parameter verwendet. SAL-Anmerkungen beschreiben auch Werte. SAL-Anmerkungen arbeiten mit dem C/C++-Codeanalysetool zusammen, um mögliche Fehler in C- und C++-Quellcode zu ermitteln. Zu den Codierungsfehlern, die das Tool am häufigsten findet, zählen Pufferüberläufe, nicht initialisierter Speicher, Dereferenzierungen von NULL-Zeigern sowie Speicher- und Ressourcenverluste.
Berücksichtigen Sie die BasicLoader::LoadMesh-Methode, die in BasicLoader.h deklariert wird. Diese Methode verwendet _In_
, um anzugeben, dass der Dateiname ein Eingabeparameter ist (und daher nur ausgelesen wird), _Out_
um anzugeben, dass vertexBuffer und indexBuffer Ausgabeparameter sind (und daher nur geschrieben werden), und _Out_opt_
um anzugeben, dass VertexCount und IndexCount optionale Ausgabeparameter sind (und möglicherweise geschrieben werden). Da vertexCount und indexCount optionale Ausgabeparameter sind, dürfen sie nullptr sein. Das C/C++-Codeanalysetool überprüft Aufrufe dieser Methode, um sicherzustellen, dass die von ihr übergebenen Parameter diese Kriterien erfüllen.
void LoadMesh(
_In_ Platform::String^ filename,
_Out_ ID3D11Buffer** vertexBuffer,
_Out_ ID3D11Buffer** indexBuffer,
_Out_opt_ uint32* vertexCount,
_Out_opt_ uint32* indexCount
);
Sie können eine Codeanalyse der App durchführen, indem Sie auf der Menüleiste auf Erstellen und anschließend auf >Codeanalyse für Lösung ausführen klicken. Weitere Informationen zur Codeanalyse finden Sie unter Analysieren der C/C++-Codequalität mithilfe der Codeanalyse.
Die vollständige Liste der verfügbaren Anmerkungen ist in sal.h definiert. Weitere Informationen finden Sie unter SAL-Anmerkungen.
Nächste Schritte
Lesen Sie die Marble Maze-Anwendungsstruktur, um Informationen darüber zu erhalten, wie der Marble Maze-Anwendungscode strukturiert ist und wie sich die Struktur einer DirectX-UWP-App von der einer herkömmlichen Desktopanwendung unterscheidet.
Zugehörige Themen