Die Beispiele für die Android Game Development Extension zeigen, wie Sie die wichtigsten Funktionen der Erweiterung verwenden. In diesem Thema werden die Beispiele und die Einstellungen beschrieben, die zum Ausführen erforderlich sind.
Die folgenden Samples sind auf der Downloadseite verfügbar:
- HelloJNI: ein Einführungsprojekt.
- Endless-Tunnel: Ein Projekt nur für Android.
- Teapot: ein plattformübergreifendes Projekt für Windows und Android.
- AssemblyCode-Link-Objects: ein Vorlagenprojekt mit Assembly-Quellcode
Vorbereitung
Installieren Sie die Android Game Development Extension und die Samples. Weitere Informationen finden Sie in der Kurzanleitung. Außerdem wird beschrieben, wie Sie ein Beispiel erstellen und ausführen. Als Beispiel wird die Android-Version des Teekannenbeispiels verwendet.
Im Leitfaden zur Projektkonfiguration wird beschrieben, wie Sie Einstellungen für ein Projekt konfigurieren, das die Erweiterung verwendet, z. B. eine Android-Plattform und ein APK hinzufügen.
HelloJNI
Das HelloJNI-Beispiel ist ein einfaches Projekt, in dem in einem App-Fenster die Nachricht „Hallo von JNI“ angezeigt wird. Das Projekt verwendet für Windows und Android unterschiedliche Quellcodes.
- Verzeichnis mit Android-Quellcode und Gradle-Build-Scripts: HelloJNI\AndroidPackaging
- Windows-Quellcode und Visual Studio-Projektverzeichnis: HelloJNI
Wenn Sie das Projekt erstellen, übergibt Visual Studio die folgenden Einstellungen an die build.gradle
-Datei auf App-Ebene. Sie können diese Einstellungen ändern, indem Sie Ihre Gradle-Build-Scripts ändern.
MSBUILD_NDK_VERSION
MSBUILD_MIN_SDK_VERSION
MSBUILD_JNI_LIBS_SRC_DIR
MSBUILD_ANDROID_OUTPUT_APK_NAME
MSBUILD_ANDROID_GRADLE_BUILD_OUTPUT_DIR
So richten Sie das Beispiel ein und führen es aus:
- Öffnen und erstellen Sie in Visual Studio das Beispiel „HelloJNI“.
- Fügen Sie die Plattform Android arm64-v8a hinzu. Weitere Informationen finden Sie unter Android-Plattform hinzufügen.
- Fügen Sie der neuen Plattform ein Android-APK-Element hinzu.
- Kompilieren Sie das Projekt.
- Fügen Sie die folgenden Android-Plattformen hinzu und fügen Sie dann jeder ein Android-APK-Element hinzu: Android-armeabi-v7a, Android-x86 und Android-x86_64.
- Erstellen und ausführen Sie das Beispiel.
Endless-Tunnel
Das Beispiel „Endless-Tunnel“ ist ein Android-Spiel, bei dem der Spieler weiße Würfel sammelt, während er versucht, das Ende eines Tunnels zu erreichen. Es wurde aus einem OpenGL-Beispiel im Android NDK-Repository auf GitHub portiert. Das Beispiel enthält keine Windows-Version des Spiels.
Die Einstellungen und Android-Plattformen für das Beispiel sind bereits konfiguriert, sodass Sie das Projekt in Visual Studio ohne Änderungen erstellen und ausführen können. Wenn Sie die Lösung öffnen, werden im Solution Explorer die folgenden Module angezeigt:
- endless-tunnel: das Anwendungsmodul, in dem die Spiellogik angezeigt wird.
- glm: ein Snapshot des OpenGL Math-Repositorys, das als statische Bibliothek erstellt wird.
- native_app_glue: ein NDK-Wrapper, der mit dem NativeActivity-Objekt kommuniziert.
Teekanne
Das Beispiel „Teapot“ zeigt eine klassische Teekanne, die mit OpenGL ES gerendert und in die Android Game Development Extension portiert wurde, um die folgenden Funktionen zu demonstrieren:
- Plattformübergreifende Projektentwicklung: Sie können das Teapot-Beispiel für Windows und Android erstellen.
- Verwendung benutzerdefinierter Android-Verpackung: Die Gradle-Build-Scripts wurden in das Stammverzeichnis des Beispiels verschoben, in dem sich die Datei
Teapot.sln
befindet. - Benutzerdefinierte Android-Konfigurationen, die die Verwendung von Address Sanitizer (ASan) und Hardware Address Sanitizer (HWASan) veranschaulichen
Die Implementierung des Teapot-Beispiels ist in mehrere Teile unterteilt, was für große plattformübergreifende Anwendungen und Spiele typisch ist:
GameApplication
-Modul: Hier werden Nutzeraktionen und Anwendungsstatus definiert, z. B. wenn ein Nutzer die Teekanne dreht oder die Anwendungsstatistiken aktualisiert.GameEngine
-Modul: Implementiert das Kern-Rendering-Modul.
Informationen zum Einrichten des Beispiels und zum Ausführen auf Android-Geräten finden Sie in der Kurzanleitung. So richten Sie das Beispiel ein und führen es unter Windows aus:
- Installieren Sie GLEW:
- Laden Sie GLEW herunter und entpacken Sie die Datei.
- Kopieren Sie die Binärdateien von
$your-glew-directory\bin\Release\x64
nach%SystemRoot%\system32
.
- Installieren Sie freeglut:
- Laden Sie freeglut herunter und entpacken Sie die Datei.
- Kopieren Sie
$your-freeglut-directory\bin\x86\freeglut.dll
nach%SystemRoot%\system32
.
- Fügen Sie die Projektabhängigkeiten von Freeglut hinzu:
- Öffnen Sie
Teapot.sln
in Visual Studio. - Klicken Sie im Menü auf Debug > x64 > Lokaler Windows-Debugger.
- Klicken Sie im Solution Explorer mit der rechten Maustaste auf GameApplication und wählen Sie Properties > C/C++ > General > Additional Include Directories aus.
- Fügen Sie dem Pfad
$your-freeglut-dir\include
hinzu.
- Klicken Sie auf OK.
- Wählen Sie Linker > Allgemein > Zusätzliche Bibliotheksverzeichnisse aus.
- Fügen Sie dem Pfad
$your-freeglut-dir\lib\x64
hinzu. - Klicken Sie auf OK.
- Wählen Sie Linker > Allgemein > Zusätzliche Bibliotheksverzeichnisse aus.
- Fügen Sie dem Pfad
freeglut.lib
hinzu. - Klicken Sie auf OK.
- Öffnen Sie
- Fügen Sie die GLEW-Projektabhängigkeiten hinzu:
- Klicken Sie im Bereich Solution Explorer mit der rechten Maustaste auf GameApplication und wählen Sie Properties > C/C++ > General > Additional Include Directories aus.
- Fügen Sie dem Pfad
$your-glew-dir\include
hinzu. - Klicken Sie auf OK.
- Wählen Sie Linker > Allgemein > Zusätzliche Bibliotheksverzeichnisse aus.
- Fügen Sie dem Pfad
$your-glew-dir\lib\Release\x86
hinzu. - Klicken Sie auf OK.
- Wählen Sie Linker > Allgemein > Zusätzliche Bibliotheksverzeichnisse aus.
- Fügen Sie dem Pfad
glew32.lib
hinzu. - Klicken Sie auf OK.
- Beispiel unter Windows ausführen:
- Klicken Sie in der Symbolleiste von Visual Studio auf die Schaltfläche „Ausführen“ des lokalen Windows-Debuggers.
- Das Muster sollte so aussehen:
AssemblyCode-Link-Objects
Dies ist ein Vorlagenprojekt, das zeigt, wie eine native Android-Bibliothek aus Assembly- und C/C++-Quellcode generiert wird. Das sind die Hauptkomponenten:
AssemblyCode-Link-Objects
: Die wichtigste native Android-Bibliothek, die aus C++- und Assembly-Quellcode erstellt wurde.StaticLib
: eine statische Hilfsbibliothek, die die Funktionfrom_static_lib_assembly_code_as
exportiert.
Das Projekt unterstützt mehrere Architekturen. Jede unterstützte Architektur hat eigene Quelldateien, in denen Funktionen implementiert sind, die aus StaticLib
exportiert werden.
Sie sollten nur die Assembly-Quelldateien für die Plattformen einschließen, die Sie erstellen. Dieses Projekt enthält Assemblydateien in Builds, die mit benutzerdefinierten Build-Tools erstellt wurden.
So richten Sie das Beispiel ein und erstellen es:
- Prüfen Sie in Visual Studio, ob benutzerdefinierte Build-Tools für die Assemblydateien konfiguriert sind:
- Klicken Sie im Solution Explorer mit der rechten Maustaste auf die Assemblydatei und dann auf Eigenschaften. Daraufhin wird das Dialogfeld Eigenschaftenseiten für die Datei geöffnet.
- Wählen Sie die Konfiguration und Plattform aus, z. B. Alle Konfigurationen für Android-arm64-v8a.
- Achten Sie darauf, dass Allgemein > Aus Build ausschließen auf Nein festgelegt ist.
- Achten Sie darauf, dass unter Allgemein > Artikeltyp Benutzerdefiniertes Build-Tool festgelegt ist.
- Klicken Sie auf Übernehmen, wenn Änderungen übernommen werden sollen.
- Prüfen Sie, ob unter Konfigurationseigenschaften > Benutzerdefinierte Build-Tools > Befehlszeile die Option
$(AsToolExe) -o "$(IntDir)%(FileName).o" %(FullPath)
festgelegt ist. Das NDK enthält einen separaten Assembler für jede CPU-Architektur und$(AsToolExe)
wird dem richtigen Assembler zugeordnet. In diesem Beispiel wird die NDK-Toolchain verwendet, um sowohl x86- als auch x86_64-Android-Projekte zu erstellen. Wenn Sie yasm für die x86_64-Android-Plattform verwenden möchten, verwenden Sie stattdessen$(YasmToolExe)
. - Konfigurationseigenschaften > Benutzerdefinierte Build-Tools > Ausgaben: muss auf
$(IntDir)%(FileName).o
festgelegt sein. Dieser String muss in der Einstellung Befehlszeile enthalten sein. - Achten Sie darauf, dass Konfigurationseigenschaften > Benutzerdefinierte Build-Tools > Objekte verknüpfen auf
Yes
gesetzt ist.
Die Einstellungen für Android-arm64-v8a sollten beispielsweise in etwa so aussehen wie im folgenden Screenshot:
- Erstellen Sie das Projekt. Dadurch wird die
libAssmeblyCodeLinkObjects.so
-Datei erstellt:- Öffnen Sie die Datei
AssemblyCode-Link-Objects.sln
. - Klicken Sie im Menü auf Erstellen > Projektmappe erstellen.
- Öffnen Sie die Datei
- Verwenden Sie das NDK-Tool nm.exe, um zu prüfen, ob die Funktionen korrekt in die Android-Bibliothek exportiert wurden:
- Wechseln Sie in der Befehlszeile zum Beispielverzeichnis.
- Rufen Sie den Speicherort der Android-Bibliothek auf, der von Ihrem Build generiert wurde. Der Standardspeicherort ähnelt
$sample_dir\$solution_configuration\$solution_platform\$platform
und$sample_dir\Debug\Android-arm64-v8a\arm64-v8a
für die Plattform arm64-v8a. - Prüfen Sie mit dem folgenden Befehl, ob der exportierte Symbolabschnitt die Funktionen enthält:
…\ndk\toolschains\llvm\prebuilt\windows-x86_64\aarch64-linux-android\bin\nm.exe --defined-only …\Debug\Android-arm64-v8a\arm64-v8a\libAssmeblyCodeLinkObjects.so
In der Ausgabe sollte eine Liste mit Symbolen angezeigt werden, die Folgendes enthalten:
T from_shared_object_assembly_code_as
T from_static_lib_assembly_code_as
PoolAllocator
Das PoolAllocator-Beispiel ist eine Android-App mit einem poolbasierten Speicherallokator, der Blöcke mit fester Größe sehr effizient bereitstellt.
Der Allocator weist bei der Initialisierung den gesamten Arbeitsspeicher mit mmap
vorab zu. Kostenlose Blöcke werden mithilfe einer verketteten Liste erfasst. Die Speicherzuweisung ist dann ein schneller O(1)
-Vorgang, der den Kopf der verknüpften Liste zurückgibt. Die Deaktivierung ist ebenfalls ein O(1)
-Vorgang, da der Block dem Ende der verknüpften Liste hinzugefügt wird.
Das Beispiel enthält zwei Lösungskonfigurationen für die Verwendung von HWASan.
HWASan
: Diese Konfiguration veranschaulicht den einfachsten Ansatz zur Verwendung von HWASan mit benutzerdefinierten Speicherallozierern. Die interne Implementierung des Speicherallokators wird durchmalloc
/free
-Aufrufe ersetzt, die automatisch von HWASan erfasst werden. Auch wenn der Speicherallokator nicht mehr als poolbasierter Allokator funktioniert, kann HWASan Ihnen dennoch helfen, wichtige Speicherfehler wie „Use-after-Free“ zu identifizieren.HWASan-Advanced
: In dieser Konfiguration wird gezeigt, wie HWASan vollständig in einen benutzerdefinierten Speicherallokator eingebunden wird, ohne den ursprünglichen Allokationsmechanismus des Allokators zu ändern. Dabei werden HWASan-Tagging-Methoden verwendet, um die Speicherblöcke im vorab zugewiesenen Pool zu taggen. Die Blockgröße wird auf eine von HWASan erforderliche Mindestblockgröße aufgerundet und die Tags werden zurückgesetzt, wenn Blöcke an den Pool zurückgegeben werden.
Verwenden Sie die HWASan
-Konfiguration, da sie einfacher ist und Ihnen helfen kann, häufige Speicherfehler zu identifizieren. Sehen Sie sich die Implementierung der HWASan-Advanced
-Konfiguration an, wenn Sie mehr über die Funktionsweise von HWASan erfahren oder die interne Semantik Ihres Speicherallokators bei Verwendung von HWASan beibehalten möchten.