Inizia a usare GameActivity Parte del Android Game Development Kit.
Questa guida descrive come configurare e integrare
GameActivity
e gestire eventi su Android.
per giocare.
GameActivity
ti aiuta a portare il tuo C o
C++ su Android semplificando il processo di utilizzo di API critiche.
In precedenza, NativeActivity
era
la classe consigliata per i giochi. GameActivity
lo sostituisce come consigliato
per i giochi ed è compatibile con le versioni precedenti al livello API 19.
Per un esempio che integra GameActivity, consulta Repository di esempi di giochi.
Prima di iniziare
Vedi le GameActivity
release per
ottenere una distribuzione.
Configura la build
Su Android, Activity
funge da voce
punto di accesso per il tuo gioco, oltre a fornire
Window
per disegnare all'interno. Molti giochi estendono
questo Activity
con la propria classe Java o Kotlin per superare le limitazioni
NativeActivity
mentre usi il codice JNI
per eseguire il bridge
al loro codice di gioco C o C++.
GameActivity
offre le seguenti funzionalità:
Eredita da
AppCompatActivity
, che ti consente di usare l'architettura Android Jetpack Componenti.Rendering
SurfaceView
che ti consente di con qualsiasi altro elemento UI Android.Consente di gestire gli eventi di attività Java. Ciò consente a qualsiasi elemento UI Android (come
EditText
, unWebView
o unAd
) per essere integrati nel tuo gioco tramite un'interfaccia C.Offre un'API C simile a
NativeActivity
eandroid_native_app_glue
libreria.
GameActivity
viene distribuito come Archivio Android
(Rivenditore autorizzato Google). Questo AAR contiene la classe Java
che utilizzi nelle
AndroidManifest.xml
e il C
e C++ che connette il lato Java di GameActivity
al
dell'implementazione C/C++. Se utilizzi GameActivity
1.2.2 o versioni successive, il pulsante C/C++
e una libreria statica. Se possibile, ti consigliamo di utilizzare
nella libreria statica anziché nel codice sorgente.
Includi questi file sorgente o la libreria statica nel tuo
il processo di compilazione
Prefab
,
che espone le librerie native e il codice sorgente ai tuoi
CMake project (Crea progetto) o NDK build.
Segui le istruzioni alla Jetpack Android Games per aggiungere il Dipendenza della raccolta
GameActivity
dal filebuild.gradle
del gioco.Attiva prefab eseguendo le seguenti operazioni con Versione del plug-in Android (AGP) 4.1 o versioni successive:
- Aggiungi quanto segue al blocco
android
del filebuild.gradle
del modulo:
buildFeatures { prefab true }
- Scegli una versione prefabbricata
e la imposto sul file
gradle.properties
:
android.prefabVersion=2.0.0
Se utilizzi versioni precedenti di AGP, segui la documentazione prefabbricata per le istruzioni di configurazione corrispondenti.
- Aggiungi quanto segue al blocco
Importa la libreria statica C/C++ o il codice sorgente C/++ nel tuo progetto come segue.
Libreria statica
Nel file
CMakeLists.txt
del progetto, importa l'elemento staticogame-activity
nel modulo prefabbricatogame-activity_static
:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)
Codice sorgente
Nel file
CMakeLists.txt
del progetto, importagame-activity
e aggiungilo al target. Il pacchettogame-activity
richiedelibandroid.so
, quindi se manca, devi importarlo.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)
Inoltre, includi i seguenti file nel file
CmakeLists.txt
del progetto:GameActivity.cpp
,GameTextInput.cpp
eandroid_native_app_glue.c
.
In che modo Android avvia la tua Attività
Il sistema Android esegue il codice nella tua istanza di attività richiamando il callback metodi che corrispondono a fasi specifiche del ciclo di vita dell'attività. Nell'ordine per Android per avviare la tua attività e iniziare il gioco, devi dichiarare la tua attività con gli attributi appropriati nel file manifest Android. Per ulteriori informazioni le informazioni, vedi Introduzione alle attività.
Manifest Android
Ogni progetto di app deve avere un AndroidManifest.xml su la radice del set di origini del progetto. Il file manifest descrive gli elementi essenziali informazioni sulla tua app agli Strumenti di sviluppo Android, al sistema operativo Android Google Play e Google Play. Ad esempio:
Nome pacchetto e ID app per identificare in modo univoco il tuo gioco su Google Play.
Componenti dell'app come di attività, servizi, broadcast receiver e fornitori di contenuti.
Autorizzazioni per accedere parti protette del sistema o altre app.
Compatibilità del dispositivo per specificare i requisiti hardware e software del tuo gioco.
Nome della libreria nativa per
GameActivity
eNativeActivity
(il valore predefinito è libmain.so).
Implementare GameActivity nel gioco
Crea o identifica la classe Java di attività principale (quella specificata nel
activity
all'interno del fileAndroidManifest.xml
). Cambia questo corso in EstendiGameActivity
dal pacchettocom.google.androidgamesdk
:import com.google.androidgamesdk.GameActivity; public class YourGameActivity extends GameActivity { ... }
Assicurati che la libreria nativa sia caricata all'inizio utilizzando un blocco statico:
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"); } ... }
Aggiungi la tua libreria nativa a
AndroidManifest.xml
se il nome della raccolta non è il nome predefinito (libmain.so
):<meta-data android:name="android.app.lib_name" android:value="android-game" />
Implementare android_main
La libreria
android_native_app_glue
è una libreria di codice sorgente che usato per gestireGameActivity
eventi del ciclo di vita in un thread separato per evitare il blocco nel thread principale. Quando usi la libreria, registri il callback per gestire gli eventi del ciclo di vita, come l'input tocco eventi. L'archivioGameActivity
include la propria versione dell'android_native_app_glue
, quindi non puoi utilizzare la versione inclusa Release NDK. Se i tuoi giochi usano la raccolta diandroid_native_app_glue
incluso nell'NDK, passa alla versioneGameActivity
.Dopo aver aggiunto il codice sorgente della libreria
android_native_app_glue
al tuo progetto, si interfaccia conGameActivity
. Implementare una funzione denominataandroid_main
, che viene chiamato dal raccolta e utilizzato come punto di accesso al tuo gioco. Viene passato un parametro chiamataandroid_app
. Questo valore potrebbe variare in base al gioco e al motore. Ecco un esempio:#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; }
Elabora
android_app
nel ciclo di gioco principale, ad esempio il sondaggio e la gestione eventi del ciclo dell'app definiti in NativeAppGlueAppCmd. Ad esempio, il seguente snippet registra la funzione_hand_cmd_proxy
comeNativeAppGlueAppCmd
, quindi esegue il polling degli eventi del ciclo dell'app e li invia al gestore registrato(inandroid_app::onAppCmd
) per l'elaborazione: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_pollAll(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(); } } }
Per ulteriori approfondimenti, esamina l'implementazione del Tunnel infinito Esempio di NDK. La differenza principale sarà il modo in cui gestire gli eventi, come mostrato in nella prossima sezione.
Gestire gli eventi
Per attivare gli eventi di input in modo che raggiungano la tua app, crea e registra il tuo evento
filtri con android_app_set_motion_event_filter
e android_app_set_key_event_filter
.
Per impostazione predefinita, la raccolta native_app_glue
consente solo gli eventi di movimento di
SOURCE_TOUCHSCREEN
di testo. Assicurati di consultare il documento di riferimento
e il codice di implementazione android_native_app_glue
per i dettagli.
Per gestire gli eventi di input, ottieni un riferimento a android_input_buffer
con
android_app_swap_input_buffers()
nel ciclo di gioco. Contengono eventi di movimento ed eventi chiave che si sono verificati dall'ultima volta che si è verificato.
con un sondaggio. Il numero di eventi contenuti viene archiviato in motionEventsCount
e
rispettivamente keyEventsCount
.
Esegui l'iterazione e gestisci ogni evento nel tuo ciclo di gioco. In questo esempio, il seguente codice esegue l'iterazione di
motionEvents
e li gestisce tramitehandle_event
: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); }
Consulta le Esempio di GitHub per l'implementazione dei
_cookEventForPointerIndex()
e di altri funzioni correlate.Al termine, ricordati di cancellare la coda degli eventi gestiti:
android_app_clear_motion_events(mApp);
Risorse aggiuntive
Per scoprire di più su GameActivity
, consulta quanto segue:
- Note di rilascio di GameActivity e AGDK.
- Usa GameTextInput in GameActivity.
- Guida alla migrazione di NativeActivity.
- Documentazione di riferimento di GameActivity.
- Implementazione di GameActivity.
Per segnalare bug o richiedere nuove funzionalità a GameActivity, utilizza il tracker dei problemi GameActivity.