Pierwsze kroki z GameActivity Zawiera Android Game Development Kit.
Z tego przewodnika dowiesz się, jak skonfigurować usługę i zintegrować ją z kontem Google.
GameActivity
i obsługuj zdarzenia na Androidzie.
tę grę.
GameActivity
pomoże Ci przenieść język C lub
z gry w C++ na Androida dzięki uproszczeniu procesu korzystania z kluczowych interfejsów API.
Wcześniej NativeActivity
był
które są zalecane w przypadku gier. GameActivity
zastępuje ją jako zalecaną
dla gier i jest zgodna wstecznie z interfejsem API poziomu 19.
Przykład integrowania aktywności GameActivity znajdziesz w tabeli games-samples.
Zanim rozpoczniesz
Zobacz GameActivity
wersji w
uzyskać dystrybucję.
Konfigurowanie kompilacji
Na Androidzie Activity
pełni funkcję wpisu
za punkty, a także
Window
, aby rysować w środku. Wiele gier rozwija się
Activity
z własną klasą Java lub Kotlin, aby
NativeActivity
podczas używania kodu JNI
do mostu
kod gry w C lub C++.
GameActivity
udostępnia te możliwości:
Dziedziczy z
AppCompatActivity
co pozwala korzystać z architektury Androida Jetpack Komponenty.Renderuje w
SurfaceView
, która umożliwia: z dowolnym elementem interfejsu Androida.Obsługuje zdarzenia związane z aktywnością w Javie. Zezwala na wszystkie elementy interfejsu Androida (takie jak
EditText
,WebView
lubAd
). zintegrowany z grą przez interfejs C.Oferuje interfejs API w wersji C podobny do
NativeActivity
orazandroid_native_app_glue
bibliotece.
Aplikacja GameActivity
jest rozpowszechniana jako archiwum Androida
(AAR). Ten plik AAR zawiera klasę Java, która
używane w
AndroidManifest.xml
, a także C
i kod źródłowy C++, który łączy GameActivity
stronę środowiska Java z
Implementacja w języku C/C++. Jeśli używasz GameActivity
w wersji 1.2.2 lub nowszej, kod C/C++
biblioteka statyczna. Jeśli jest to możliwe, zalecamy użycie ciągu
biblioteki statycznej zamiast kodu źródłowego.
Uwzględnij te pliki źródłowe lub bibliotekę statyczną jako część
procesu tworzenia kampanii
Prefab
który ujawnia biblioteki natywne i kod źródłowy
Utwórz projekt lub kompilację NDK.
Postępuj zgodnie z instrukcjami na stronie Jetpack Android Games, aby dodać zależność biblioteki
GameActivity
od plikubuild.gradle
gry.Włącz prefab, wykonując te czynności: Wersja wtyczki Android (AGP) 4.1 lub nowsza:
- Do bloku
android
w plikubuild.gradle
modułu dodaj:
buildFeatures { prefab true }
- Wybierz wersję z prefab,
i ustaw go na plik
gradle.properties
:
android.prefabVersion=2.0.0
Jeśli używasz starszych wersji AGP, postępuj zgodnie z dokumentację wstępną z użyciem odpowiednich instrukcji konfiguracji.
- Do bloku
Zaimportuj bibliotekę statyczną C/C++ lub kod źródłowy C/++ w następujący sposób.
Biblioteka statyczna
W pliku
CMakeLists.txt
projektu zaimportuj statyczny element typugame-activity
do modułu prefabgame-activity_static
:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)
Kod źródłowy
Do pliku
CMakeLists.txt
projektu zaimportujgame-activity
i dodaj go do miejsca docelowego. Pakietgame-activity
wymagalibandroid.so
, więc jeśli go brakuje, musisz go też zaimportować.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)
Do folderu
CmakeLists.txt
projektu dołącz też te pliki:GameActivity.cpp
,GameTextInput.cpp
iandroid_native_app_glue.c
.
Jak Android uruchamia Twoją aktywność
System Android wykonuje kod w wystąpieniu aktywności, wywołując wywołanie zwrotne. które odpowiadają konkretnym etapom cyklu życia aktywności. W zamówieniu na Androida, aby uruchomić aktywność i grę, musisz zadeklarować Twojej aktywności za pomocą odpowiednich atrybutów z pliku manifestu Androida. Więcej Więcej informacji zawiera Wprowadzenie do modułów
Plik manifestu Androida
Każdy projekt aplikacji musi mieć plik AndroidManifest.xml w lokalizacji elementu głównego zbioru źródłowego projektu. Plik manifestu opisuje informacje o aplikacji, narzędzia do kompilacji Androida, system operacyjny Android system i Google Play. Przykładowe zabezpieczenia:
Nazwa pakietu i identyfikator aplikacji jednoznacznie identyfikują grę w Google Play.
Komponenty aplikacji: aktywności, usług, odbiorników i dostawców treści.
Uprawnienia dostępu. chronionych części systemu lub innych aplikacji.
Zgodność urządzeń aby określić wymagania sprzętowe i oprogramowania gry.
Nazwa biblioteki natywnej dla
GameActivity
iNativeActivity
(domyślnie libmain.so).
Wdróż aktywność w grze w swojej grze
Utwórz lub zidentyfikuj swoją główną klasę Java (określoną w tagu
activity
w plikuAndroidManifest.xml
). Zmień te zajęcia na rozszerzGameActivity
z pakietucom.google.androidgamesdk
:import com.google.androidgamesdk.GameActivity; public class YourGameActivity extends GameActivity { ... }
Upewnij się, że biblioteka natywna została wczytana na początku przy użyciu bloku statycznego:
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"); } ... }
Dodawanie biblioteki natywnej do
AndroidManifest.xml
jeśli nazwa biblioteki nie jest nazwą domyślną (libmain.so
):<meta-data android:name="android.app.lib_name" android:value="android-game" />
Wdróż android_main
Biblioteka
android_native_app_glue
to biblioteka kodu źródłowego, gra używa do zarządzaniaGameActivity
zdarzeniami cyklu życia w osobnym wątku w aby zapobiec zablokowaniu treści w wątku głównym. Podczas korzystania z biblioteki rejestrujesz wywołanie zwrotne do obsługi zdarzeń cyklu życia, takich jak dotykowe wprowadzanie danych zdarzeń. ArchiwumGameActivity
zawiera własną wersję plikuandroid_native_app_glue
, więc nie możesz korzystać z wersji zawartej w wersje NDK. Jeśli Twoje gry korzystają z bibliotekiandroid_native_app_glue
które jest zawarte w NDK, przejdź na wersjęGameActivity
.Po dodaniu kodu źródłowego biblioteki
android_native_app_glue
do projekt, łączy się on z zasadąGameActivity
. Zaimplementować funkcję o nazwieandroid_main
, które jest wywoływane przez i używać jej jako punktu wejścia w grę. Powodzenie o nazwieandroid_app
. Może się to różnić w zależności od gry i silnika. Oto przykład:#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; }
Przetwarzaj obiekt
android_app
w głównej pętli gry, np. w ankietach i obsłudze. zdarzeń cyklu aplikacji zdefiniowane w kombinacji NativeAppGlueAppCmd. Na przykład ten fragment kodu rejestruje funkcję_hand_cmd_proxy
jakoNativeAppGlueAppCmd
, a następnie sonduje zdarzenia cyklu aplikacji i wysyła je do zarejestrowany moduł obsługi(w:android_app::onAppCmd
) na potrzeby przetwarzania: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(); } } }
Więcej informacji znajdziesz w opisie wdrożenia niekończącego się tunelu. Przykład NDK. Główna różnica będzie polegać na obsłudze zdarzeń przejdź do następnej sekcji.
Obsługa zdarzeń
Aby umożliwić dostęp do aplikacji zdarzenia wejściowe, utwórz i zarejestruj zdarzenie
filtry z android_app_set_motion_event_filter
i android_app_set_key_event_filter
.
Domyślnie biblioteka native_app_glue
zezwala na zdarzenia ruchu tylko z
SOURCE_TOUCHSCREEN
dane wejściowe. Zapoznaj się z dokumentem referencyjnym
i kod implmenetyki android_native_app_glue
, by uzyskać szczegóły.
Aby obsługiwać zdarzenia wejściowe, uzyskaj odniesienie do elementu android_input_buffer
z parametrem
android_app_swap_input_buffers()
.
w pętli gry. Obejmują one zdarzenia ruchu i kluczowe zdarzenia, które miały miejsce od ostatniego zdarzenia.
Liczba zdarzeń jest przechowywana w motionEventsCount
,
keyEventsCount
.
Wykonuj iteracje i obsługuj każde zdarzenie w pętli gry. W tym przykładzie para klucz-wartość ten kod wykona iterację
motionEvents
i obsługuje je za pomocąhandle_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); }
Zobacz Przykład z GitHub dla implementacji
_cookEventForPointerIndex()
i innych z powiązanych funkcji.Gdy skończysz, pamiętaj o wyczyszczeniu kolejki zdarzeń, które zostały niedawno obsługiwane:
android_app_clear_motion_events(mApp);
Dodatkowe materiały
Więcej informacji o funkcji GameActivity
:
- Informacje o wersji GameActivity i AGDK
- Użyj GameTextInput w sekcji GameActivity.
- Przewodnik po migracji do NativeActivity.
- Dokumentacja GameActivity.
- Implementacja GameActivity.
Aby zgłosić błędy lub poprosić o nowe funkcje w GameActivity, skorzystaj z narzędzia do zgłaszania problemów w GameActivity.