Erste Schritte mit GameActivity Teil des Android Game Development Kit.
In dieser Anleitung wird beschrieben, wie Sie
GameActivity einrichten und in Ihr Android
Spiel einbinden und wie Sie Ereignisse in Ihrem Android
Spiel verarbeiten.
GameActivity vereinfacht die Verwendung wichtiger APIs und hilft Ihnen so, Ihr C- oder C++-Spiel auf Android zu bringen.
Bisher war NativeActivity die empfohlene Klasse für Spiele. GameActivity ersetzt sie als empfohlene Klasse für Spiele und ist abwärtskompatibel bis API-Level 19.
Ein Beispiel für die Einbindung von GameActivity finden Sie im Repository games-samples.
Vorbereitung
Informationen zum Abrufen einer Verteilung finden Sie unter GameActivity Releases
Build einrichten
Unter Android dient ein Activity als Einstieg
spunkt für Ihr Spiel und stellt auch das
Window bereit, in dem gezeichnet wird. Viele Spiele erweitern
diese Activity mit einer eigenen Java- oder Kotlin-Klasse, um Einschränkungen in
NativeActivity zu umgehen und gleichzeitig JNI-Code zu verwenden, um eine Verbindung
zu ihrem C- oder C++-Spielcode herzustellen.
GameActivity bietet die folgenden Funktionen:
Erbt von
AppCompatActivity, sodass Sie Android Jetpack-Architektur Komponenten verwenden können.Wird in einer
SurfaceViewgerendert, mit der Sie mit jedem anderen Android-UI-Element interagieren können.Verarbeitet Java-Aktivitätsereignisse. So kann jedes Android-UI-Element (z. B. ein
EditText, einWebViewoder eineAd) über eine C-Schnittstelle in Ihr Spiel eingebunden werden.Bietet eine C-API ähnlich der
NativeActivityund derandroid_native_app_glueBibliothek.
GameActivity wird als Android-Archiv
(AAR) verteilt. Dieses AAR enthält die Java-Klasse, die
Sie in Ihrer
AndroidManifest.xml verwenden, sowie den C
und C++-Quellcode, der die Java-Seite von GameActivity mit der C/C++-Implementierung der App verbindet. Wenn Sie GameActivity 1.2.2 oder höher verwenden, wird auch die statische C/C++-Bibliothek bereitgestellt. Sofern möglich, empfehlen wir, die statische Bibliothek anstelle des Quellcodes zu verwenden.
Nehmen Sie diese Quelldateien oder die statische Bibliothek über
Ihren
PrefabBuild-Prozess auf.
Dadurch werden native Bibliotheken und Quellcode für Ihr
CMake-Projekt oder Ihren NDK-Build verfügbar gemacht.
Folgen Sie der Anleitung auf der Jetpack Android Games-Seite, um die
GameActivityBibliotheksabhängigkeit derbuild.gradle-Datei Ihres Spiels hinzuzufügen.Aktivieren Sie Prefab mit den folgenden Schritten für das Android-Plug-in (AGP) 4.1 und höher:
- Fügen Sie dem Block
androidderbuild.gradle-Datei Ihres Moduls Folgendes hinzu:
buildFeatures { prefab true }- Wählen Sie eine Prefab-Version,
und legen Sie sie in der Datei
gradle.propertiesfest:
android.prefabVersion=2.0.0Wenn Sie frühere AGP-Versionen verwenden, folgen Sie der Prefab-Dokumentation für die entsprechenden Konfigurationsanweisungen.
- Fügen Sie dem Block
Importieren Sie die statische C/C++-Bibliothek oder den C/C++-Quellcode wie folgt in Ihr Projekt.
Statische Bibliothek
Importieren Sie in der Datei
CMakeLists.txtIhres Projekts die statische Bibliothekgame-activityin das Prefab-Modulgame-activity_static:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)Quellcode
Importieren Sie in der Datei
CMakeLists.txtIhres Projekts das Paketgame-activityund fügen Sie es Ihrem Ziel hinzu. Für das Paketgame-activityistlibandroid.soerforderlich. Wenn es fehlt, müssen Sie es auch importieren.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)Fügen Sie außerdem die folgenden Dateien in die Datei
CmakeLists.txtIhres Projekts ein:GameActivity.cpp,GameTextInput.cppundandroid_native_app_glue.c.
So startet Android Ihre Aktivität
Das Android-System führt Code in Ihrer Aktivitätsinstanz aus, indem es Callback-Methoden aufruft, die bestimmten Phasen des Aktivitätslebenszyklus entsprechen. Damit Android Ihre Aktivität starten und Ihr Spiel starten kann, müssen Sie Ihre Aktivität mit den entsprechenden Attributen im Android-Manifest deklarieren. Weitere Informationen finden Sie unter Einführung in Aktivitäten.
Android-Manifest
Jedes App-Projekt muss eine AndroidManifest.xml Datei im Stammverzeichnis des Source-Sets des Projekts haben. Die Manifestdatei enthält wichtige Informationen zu Ihrer App für die Android-Build-Tools, das Android-Betriebssystem und Google Play. Dazu zählen:
Paketname und App-ID zur eindeutigen Identifizierung Ihres Spiels bei Google Play.
App-Komponenten wie Aktivitäten, Dienste, Broadcast-Empfänger und Content-Provider.
Berechtigungen für den Zugriff auf geschützte Teile des Systems oder andere Apps.
Gerätekompatibilität um Hardware- und Softwareanforderungen für Ihr Spiel festzulegen.
Name der nativen Bibliothek für
GameActivityundNativeActivity(Standard ist libmain.so).
GameActivity in Ihrem Spiel implementieren
Erstellen oder identifizieren Sie die Java-Klasse Ihrer Hauptaktivität (die im Element
activityin IhrerAndroidManifest.xml-Datei angegeben ist). Ändern Sie diese Klasse so, dass sieGameActivityaus dem Paketcom.google.androidgamesdkerweitert:import com.google.androidgamesdk.GameActivity; public class YourGameActivity extends GameActivity { ... }Achten Sie darauf, dass Ihre native Bibliothek zu Beginn mit einem statischen Block geladen wird:
public class EndlessTunnelActivity extends GameActivity { static { // Load the native library. // The name "android-game" depends on your CMake configuration, must be // consistent here and inside AndroidManifect.xml System.loadLibrary("android-game"); } ... }Fügen Sie Ihre native Bibliothek zu
AndroidManifest.xmlhinzu, wenn der Bibliotheksname nicht der Standardname (libmain.so) ist:<meta-data android:name="android.app.lib_name" android:value="android-game" />
android_main implementieren
Die Bibliothek
android_native_app_glueist eine Quellcodebibliothek, die Ihr Spiel verwendet, umGameActivity-Lebenszyklusereignisse in einem separaten Thread zu verwalten, um Blockierungen im Hauptthread zu vermeiden. Wenn Sie die Bibliothek verwenden, registrieren Sie den Callback, um Lebenszyklusereignisse wie Touch-Eingabe ereignisse zu verarbeiten. Das ArchivGameActivityenthält eine eigene Version der Bibliothekandroid_native_app_glue. Sie können also nicht die Version verwenden, die in NDK-Releases enthalten ist. Wenn Ihre Spiele die Bibliothekandroid_native_app_glueverwenden, die im NDK enthalten ist, wechseln Sie zurGameActivity-Version.Nachdem Sie den Quellcode der Bibliothek
android_native_app_glueIhrem Projekt hinzugefügt haben, wird eine Verbindung zuGameActivityhergestellt. Implementieren Sie eine Funktion namensandroid_main, die von der Bibliothek aufgerufen wird und als Einstiegspunkt für Ihr Spiel dient. Ihr wird eine Struktur namensandroid_appübergeben. Dies kann je nach Spiel und Engine variieren. Beispiel:#include <game-activity/native_app_glue/android_native_app_glue.h> extern "C" { void android_main(struct android_app* state); }; void android_main(struct android_app* app) { NativeEngine *engine = new NativeEngine(app); engine->GameLoop(); delete engine; }Verarbeiten Sie
android_appin Ihrer Hauptspielschleife, z. B. durch Abrufen und Verarbeiten von App-Lebenszyklusereignissen, die in NativeAppGlueAppCmd definiert sind. Im folgenden Beispiel wird die Funktion_hand_cmd_proxyals Handler fürNativeAppGlueAppCmdregistriert. Anschließend werden App-Lebenszyklusereignisse abgerufen und zur Verarbeitung an den registrierten Handler(inandroid_app::onAppCmd) gesendet:void NativeEngine::GameLoop() { mApp->userData = this; mApp->onAppCmd = _handle_cmd_proxy; // register your command handler. mApp->textInputState = 0; while (1) { int events; struct android_poll_source* source; // If not animating, block until we get an event; // If animating, don't block. while ((ALooper_pollOnce(IsAnimating() ? 0 : -1, NULL, &events, (void **) &source)) >= 0) { if (source != NULL) { // process events, native_app_glue internally sends the outstanding // application lifecycle events to mApp->onAppCmd. source->process(source->app, source); } if (mApp->destroyRequested) { return; } } if (IsAnimating()) { DoFrame(); } } }Weitere Informationen finden Sie in der Implementierung des Endless Tunnel NDK-Beispiels. Der Hauptunterschied besteht darin, wie Ereignisse verarbeitet werden, wie im nächsten Abschnitt gezeigt.
Ereignisse verarbeiten
Damit Eingabeereignisse Ihre App erreichen können, erstellen und registrieren Sie Ihre Ereignis
filter mit android_app_set_motion_event_filter
und android_app_set_key_event_filter.
Standardmäßig lässt die native_app_glue Bibliothek nur Bewegungsereignisse von der
SOURCE_TOUCHSCREEN
Eingabe zu. Weitere Informationen finden Sie in der Referenzdokumentation
und im android_native_app_glue Implementierungscode.
Um Eingabeereignisse zu verarbeiten, rufen Sie in Ihrer Spielschleife mit
android_app_swap_input_buffers()
einen Verweis auf den android_input_buffer ab. Diese enthalten Bewegungsereignisse und Schlüsselereignisse, die seit dem letzten Abruf aufgetreten sind. Die Anzahl der enthaltenen Ereignisse wird in motionEventsCount bzw. keyEventsCount gespeichert.
Wiederholen Sie die einzelnen Ereignisse in Ihrer Spielschleife und verarbeiten Sie sie. In diesem Beispiel werden die
motionEventsmit dem folgenden Code wiederholt und überhandle_eventverarbeitet:android_input_buffer* inputBuffer = android_app_swap_input_buffers(app); if (inputBuffer && inputBuffer->motionEventsCount) { for (uint64_t i = 0; i < inputBuffer->motionEventsCount; ++i) { GameActivityMotionEvent* motionEvent = &inputBuffer->motionEvents[i]; if (motionEvent->pointerCount > 0) { const int action = motionEvent->action; const int actionMasked = action & AMOTION_EVENT_ACTION_MASK; // Initialize pointerIndex to the max size, we only cook an // event at the end of the function if pointerIndex is set to a valid index range uint32_t pointerIndex = GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT; struct CookedEvent ev; memset(&ev, 0, sizeof(ev)); ev.motionIsOnScreen = motionEvent->source == AINPUT_SOURCE_TOUCHSCREEN; if (ev.motionIsOnScreen) { // use screen size as the motion range ev.motionMinX = 0.0f; ev.motionMaxX = SceneManager::GetInstance()->GetScreenWidth(); ev.motionMinY = 0.0f; ev.motionMaxY = SceneManager::GetInstance()->GetScreenHeight(); } switch (actionMasked) { case AMOTION_EVENT_ACTION_DOWN: pointerIndex = 0; ev.type = COOKED_EVENT_TYPE_POINTER_DOWN; break; case AMOTION_EVENT_ACTION_POINTER_DOWN: pointerIndex = ((action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); ev.type = COOKED_EVENT_TYPE_POINTER_DOWN; break; case AMOTION_EVENT_ACTION_UP: pointerIndex = 0; ev.type = COOKED_EVENT_TYPE_POINTER_UP; break; case AMOTION_EVENT_ACTION_POINTER_UP: pointerIndex = ((action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); ev.type = COOKED_EVENT_TYPE_POINTER_UP; break; case AMOTION_EVENT_ACTION_MOVE: { // Move includes all active pointers, so loop and process them here, // we do not set pointerIndex since we are cooking the events in // this loop rather than at the bottom of the function ev.type = COOKED_EVENT_TYPE_POINTER_MOVE; for (uint32_t i = 0; i < motionEvent->pointerCount; ++i) { _cookEventForPointerIndex(motionEvent, callback, ev, i); } break; } default: break; } // Only cook an event if we set the pointerIndex to a valid range, note that // move events cook above in the switch statement. if (pointerIndex != GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT) { _cookEventForPointerIndex(motionEvent, callback, ev, pointerIndex); } } } android_app_clear_motion_events(inputBuffer); }Die Implementierung von
_cookEventForPointerIndex()und anderen zugehörigen Funktionen finden Sie im GitHub-Beispiel.Wenn Sie fertig sind, leeren Sie die Warteschlange der gerade verarbeiteten Ereignisse:
android_app_clear_motion_events(mApp);
Zusätzliche Ressourcen
Weitere Informationen zu GameActivity finden Sie unter:
- Versionshinweise zu GameActivity und AGDK.
- GameTextInput in GameActivity verwenden.
- Migrationsanleitung für NativeActivity.
- Referenzdokumentation zu GameActivity.
- GameActivity-Implementierung
Wenn Sie Fehler melden oder neue Funktionen für GameActivity anfordern möchten, verwenden Sie die Problemverfolgung für GameActivity.