Effectuer une migration depuis NativeActivity composante de l'Android Game Development Kit
Cette page explique comment migrer de NativeActivity
vers GameActivity
dans votre projet de jeu Android.
GameActivity
est basé sur NativeActivity
, du framework Android, mais offre plusieurs améliorations et nouvelles fonctionnalités :
- Compatible avec l'élément
Fragment
, de Jetpack. - Compatible avec
TextInput
pour faciliter l'intégration des claviers virtuels. - Gère les événements associés aux gestes tactiles et aux touches dans la classe Java
GameActivity
plutôt que dans l'interfaceonInputEvent
deNativeActivity
.
Avant de procéder à la migration, nous vous recommandons de lire le guide de démarrage, qui explique comment configurer et intégrer GameActivity
à votre projet.
Mises à jour du script de compilation Java
GameActivity
est distribué en tant que bibliothèque Jetpack. Veillez à appliquer la procédure de mise à jour du script Gradle décrite dans le guide de démarrage :
Activez la bibliothèque Jetpack dans le fichier
gradle.properties
de votre projet :android.useAndroidX=true
Vous pouvez également spécifier une version de Prefab dans le même fichier
gradle.properties
, par exemple :android.prefabVersion=2.0.0
Activez la fonctionnalité Prefab dans le fichier
build.gradle
de votre application :android { ... // other configurations buildFeatures.prefab true }
Ajoutez la dépendance
GameActivity
à votre application :- Ajoutez les bibliothèques
core
etgames-activity
. - Si votre niveau d'API minimal actuellement accepté est inférieur à 16, procédez à sa mise à jour vers cette version ou une version ultérieure.
- Mettez à jour la version du SDK compilée pour obtenir celle qui est requise par la bibliothèque
games-activity
. Jetpack nécessite généralement la dernière version du SDK au moment de la compilation de la version.
Votre fichier
build.gradle
mis à jour peut se présenter comme suit :android { compiledSdkVersion 33 ... // other configurations. defaultConfig { minSdkVersion 16 } ... // other configurations. buildFeatures.prefab true } dependencies { implementation 'androidx.core:core:1.9.0' implementation 'androidx.games:games-activity:1.2.2' }
- Ajoutez les bibliothèques
Mises à jour du code Kotlin ou Java
L'élément NativeActivity
peut être utilisé comme activité de démarrage et crée une application plein écran. Actuellement, il est impossible d'utiliser GameActivity comme activité de démarrage. Les applications doivent créer une classe dérivée de GameActivity
et l'utiliser comme activité de démarrage. Vous devez également apporter des modifications de configuration supplémentaires pour créer une application plein écran.
Les étapes suivantes supposent que votre application utilise NativeActivity
comme activité de démarrage. Si ce n'est pas le cas, vous pouvez en ignorer la majorité.
Créez un fichier Kotlin ou Java pour héberger la nouvelle activité de démarrage. Par exemple, le code suivant crée
MainActivity
en tant qu'activité de démarrage et charge la principale bibliothèque native de l'application,libAndroidGame.so
:Kotlin
class MainActivity : GameActivity() { override fun onResume() { super.onResume() // Use the function recommended from the following page: // https://d.android.com/training/system-ui/immersive hideSystemBars() } companion object { init { System.loadLibrary("AndroidGame") } } }
Java
public class MainActivity extends GameActivity { protected void onResume() { super.onResume(); // Use the function recommended from // https://d.android.com/training/system-ui/immersive hideSystemBars(); } static { System.loadLibrary("AndroidGame"); } }
Créez un thème d'application en plein écran dans le fichier
res\values\themes.xml
:<resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> <style name="Application.Fullscreen" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowFullscreen">true</item> <item name="android:windowContentOverlay">@null</item>" </style> </resources>
Appliquez le thème à l'application dans le fichier
AndroidManifest.xml
:<application android:theme=”@style/Application.Fullscreen”> <!-- other configurations not listed here. --> </application>
Pour obtenir des instructions détaillées sur le mode plein écran, consultez le guide immersif et l'exemple d'implémentation qui figure dans le dépôt game-samples.
Ce guide de migration ne modifie pas le nom de la bibliothèque native. Si vous décidez de le modifier, assurez-vous que les noms des bibliothèques natives sont les mêmes aux trois emplacements suivants :
Code Kotlin ou Java :
System.loadLibrary(“AndroidGame”)
AndroidManifest.xml
:<meta-data android:name="android.app.lib_name" android:value="AndroidGame" />
Dans le fichier de script de compilation C/C++, par exemple
CMakeLists.txt
:add_library(AndroidGame ...)
Mises à jour de script de compilation C/C++
Les instructions de cette section utilisent cmake
comme exemple. Si votre application utilise ndk-build
, ajustez ces instructions avec commandes équivalentes décrites à la page de documentation de ndk-build.
L'implémentation C/C++ de GameActivity fournit une version de code source. À partir de la version 1.2.2, une version de bibliothèque statique est fournie. La bibliothèque statique est le type de version recommandé.
La version est intégrée à l'AAR avec l'utilitaire prefab
. Le code natif inclut les sources C/C++ de GameActivity et le code native_app_glue
. Ils doivent être compilés avec le code C/C++ de votre application.
Les applications NativeActivity
utilisent déjà le code native_app_glue
présent dans NDK. Vous devez le remplacer par la version de native_app_glue
de GameActivity. En dehors de cela, toutes les opérations cmake
décrites dans le guide de démarrage s'appliquent :
Importez la bibliothèque statique C/C++ ou le code source C/++ dans votre projet comme suit.
Bibliothèque statique
Dans le fichier
CMakeLists.txt
de votre projet, importez la bibliothèque statiquegame-activity
dans le module Prefabgame-activity_static
:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)
Code source
Dans le fichier
CMakeLists.txt
de votre projet, importez le packagegame-activity
et ajoutez-le à votre cible. Le packagegame-activity
nécessitelibandroid.so
. S'il est absent, vous devez donc également l'importer.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)
Supprimez toutes les références au code
native_app_glue
de NDK, telles que :${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ... set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")
Si vous utilisez la version du code source, incluez les fichiers sources
GameActivity
. Sinon, ignorez cette étape.get_target_property(game-activity-include game-activity::game-activity INTERFACE_INCLUDE_DIRECTORIES) add_library(${PROJECT_NAME} SHARED main.cpp ${game-activity-include}/game-activity/native_app_glue/android_native_app_glue.c ${game-activity-include}/game-activity/GameActivity.cpp ${game-activity-include}/game-text-input/gametextinput.cpp)
Résoudre une erreur UnsatisfactionLinkError
Si vous rencontrez une UnsatsifiedLinkError
pour la fonction com.google.androidgamesdk.GameActivity.initializeNativeCode()
, ajoutez ce code à votre fichier CMakeLists.txt
:
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u \
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")
Mises à jour du code source C/C++
Procédez comme suit pour remplacer les références NativeActivity
dans votre application par GameActivity
:
Utilisez l'élément
native_app_glue
publié avecGameActivity
. Recherchez et remplacez toute utilisation deandroid_native_app_glue.h
par :#include <game-activity/native_app_glue/android_native_app_glue.h>
Définissez le filtre d'événement de mouvement et le filtre d'événement de touche sur
NULL
pour que votre application puisse recevoir les événements, quel que soit le périphérique d'entrée. Cette opération s'effectue généralement dans la fonctionandroid_main()
:void android_main(android_app* app) { ... // other init code. android_app_set_key_event_filter(app, NULL); android_app_set_motion_event_filter(app, NULL); ... // additional init code, and game loop code. }
Supprimez le code associé
AInputEvent
, puis remplacez-le par l'implémentationInputBuffer
de GameActivity :while (true) { // Read all pending events. int events; struct android_poll_source* source; // If not animating, block forever waiting for events. // If animating, loop until all events are read, then continue // to draw the next frame of animation. while ((ALooper_pollAll(engine.animating ? 0 : -1, nullptr, &events, (void**)&source)) >= 0) { // Process this app cycle or inset change event. if (source) { source->process(source->app, source); } ... // Other processing. // Check if app is exiting. if (state->destroyRequested) { engine_term_display(&engine); return; } } // Process input events if there are any. engine_handle_input(state); if (engine.animating) { // Draw a game frame. } } // Implement input event handling function. static int32_t engine_handle_input(struct android_app* app) { auto* engine = (struct engine*)app->userData; auto ib = android_app_swap_input_buffers(app); if (ib && ib->motionEventsCount) { for (int i = 0; i < ib->motionEventsCount; i++) { auto *event = &ib->motionEvents[i]; int32_t ptrIdx = 0; switch (event->action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_UP: // Retrieve the index for the starting and the ending of any secondary pointers ptrIdx = (event->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: engine->state.x = GameActivityPointerAxes_getAxisValue( &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X); engine->state.y = GameActivityPointerAxes_getAxisValue( &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y); break; case AMOTION_EVENT_ACTION_MOVE: // Process the move action: the new coordinates for all active touch pointers // are inside the event->pointers[]. Compare with our internally saved // coordinates to find out which pointers are actually moved. Note that there is // no index embedded inside event->action for AMOTION_EVENT_ACTION_MOVE (there // might be multiple pointers moved at the same time). ... break; } } android_app_clear_motion_events(ib); } // Process the KeyEvent in a similar way. ... return 0; }
Examinez et mettez à jour la logique associée au
AInputEvent
d'activité native. Comme indiqué à l'étape précédente, le traitementInputBuffer
de GameActivity n'est pas exécuté dans la boucleALooper_pollAll()
.Remplacez l'utilisation de
android_app::activity->clazz
parandroid_app:: activity->javaGameActivity
. GameActivity renomme l'instance JavaGameActivity
.
Étapes supplémentaires :
Les opérations précédentes décrivent les fonctionnalités de NativeActivity, mais GameActivity
propose des fonctionnalités supplémentaires qui peuvent vous être utiles :
- TextInput
- Manette de jeu
- Fragment
- Nouvelles commandes InSet de fenêtre définies dans NativeAppGlueAppCmd.
Nous vous recommandons d'essayer ces fonctionnalités et de les adopter si elles sont appropriées pour vos jeux.
Si vous avez des questions ou des recommandations concernant GameActivity ou d'autres bibliothèques AGDK, créez un rapport de bug pour nous en informer.