GameActivity'yi kullanmaya başlama Android Game Development Kit'in bir parçasıdır.
Bu kılavuzda, Android oyununuzda GameActivity'i nasıl ayarlayacağınız ve entegre edeceğiniz ile etkinlikleri nasıl işleyeceğiniz açıklanmaktadır.
GameActivity, kritik API'leri kullanma sürecini basitleştirerek C veya C++ oyununuzu Android'e taşımanıza yardımcı olur.
Daha önce oyunlar için önerilen sınıf NativeActivity idi. GameActivity, oyunlar için önerilen sınıf olarak bunun yerini alıyor ve API düzeyi 19 ile geriye dönük olarak uyumlu.
GameActivity'yi entegre eden bir örnek için games-samples deposuna bakın.
Başlamadan önce
Dağıtım almak için GameActivity sürümlerine bakın.
Derlemenizi ayarlama
Android'de Activity, oyununuzun giriş noktası olarak işlev görür ve aynı zamanda çizim yapmak için Window sağlar. Birçok oyun, C veya C++ oyun kodlarına köprü oluşturmak için JNI kodunu kullanırken NativeActivity sınırlamalarını aşmak amacıyla bu Activity öğesini kendi Java veya Kotlin sınıfıyla genişletir.
GameActivity aşağıdaki özellikleri sunar:
AppCompatActivityöğesinden devralınır. Bu sayede Android Jetpack Architecture Components'ı kullanabilirsiniz.Diğer Android kullanıcı arayüzü öğeleriyle arayüz oluşturmanıza olanak tanıyan bir
SurfaceViewolarak oluşturulur.Java etkinliklerini işler. Bu sayede, herhangi bir Android kullanıcı arayüzü öğesinin (ör.
EditText,WebViewveyaAd) C arayüzü üzerinden oyununuza entegre edilmesini sağlar.NativeActivityveandroid_native_app_gluekitaplığına benzer bir C API sunar.
GameActivity, Android Arşivi (AAR) olarak dağıtılır. Bu AAR, AndroidManifest.xml içinde kullandığınız Java sınıfının yanı sıra GameActivity'ın Java tarafını uygulamanın C/C++ uygulamasına bağlayan C ve C++ kaynak kodunu içerir. GameActivity 1.2.2 veya sonraki bir sürümü kullanıyorsanız C/C++ statik kitaplığı da sağlanır. Mümkün olduğunda kaynak kodu yerine statik kitaplığı kullanmanızı öneririz.
Bu kaynak dosyaları veya statik kitaplığı, Prefab aracılığıyla derleme işleminize dahil edin. Bu araç, yerel kitaplıkları ve kaynak kodu CMake projenize veya NDK derlemenize sunar.
GameActivitykitaplık bağımlılığını oyununuzunbuild.gradledosyasına eklemek için Jetpack Android Games sayfasındaki talimatları uygulayın.Android Plugin Version (AGP) 4.1 ve sonraki sürümler ile aşağıdaki adımları uygulayarak prefab'i etkinleştirin:
- Modülünüzün
build.gradledosyasınınandroidbloğuna aşağıdakileri ekleyin:
buildFeatures { prefab true }- Prefab sürümü seçin ve
gradle.propertiesdosyasına ayarlayın:
android.prefabVersion=2.0.0Daha eski AGP sürümlerini kullanıyorsanız ilgili yapılandırma talimatları için prefab belgelerini inceleyin.
- Modülünüzün
C/C++ statik kitaplığını veya C/++ kaynak kodunu projenize aşağıdaki şekilde aktarın.
Statik kitaplık
Projenizin
CMakeLists.txtdosyasında,game-activitystatic kitaplığınıgame-activity_staticprefab modülüne aktarın:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)Kaynak kodu
Projenizin
CMakeLists.txtdosyasındagame-activitypaketini içe aktarın ve hedefinize ekleyin.game-activitypaketilibandroid.sogerektirir. Bu nedenle, eksikse onu da içe aktarmanız gerekir.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)Ayrıca, aşağıdaki dosyaları projenizin
CmakeLists.txtbölümüne ekleyin:GameActivity.cpp,GameTextInput.cppveandroid_native_app_glue.c.
Android, etkinliğinizi nasıl başlatır?
Android sistemi, etkinlik yaşam döngüsünün belirli aşamalarına karşılık gelen geri çağırma yöntemlerini çağırarak Etkinlik örneğinizdeki kodu yürütür. Android'in etkinliğinizi başlatıp oyununuzu başlatabilmesi için etkinliğinizi Android manifest dosyasında uygun özelliklerle tanımlamanız gerekir. Daha fazla bilgi için Etkinliklere Giriş başlıklı makaleyi inceleyin.
Android Manifesti
Her uygulama projesinin, proje kaynak grubunun kökünde bir AndroidManifest.xml dosyası olmalıdır. Manifest dosyası, Android derleme araçlarına, Android işletim sistemine ve Google Play'e uygulamanızla ilgili temel bilgileri açıklar. Bunlardan bazıları:
Google Play'de oyununuzu benzersiz şekilde tanımlamak için paket adı ve uygulama kimliği.
Etkinlikler, hizmetler, yayın alıcıları ve içerik sağlayıcılar gibi uygulama bileşenleri.
Sistemin korumalı bölümlerine veya diğer uygulamalara erişmek için izinler.
Oyununuzun donanım ve yazılım gereksinimlerini belirtmek için cihaz uyumluluğu.
GameActivityveNativeActivityiçin yerel kitaplık adı(varsayılan değer libmain.so).
Oyununuza GameActivity'yi uygulama
Ana etkinlik Java sınıfınızı oluşturun veya tanımlayın (
AndroidManifest.xmldosyanızdakiactivityöğesinde belirtilen sınıf). Bu sınıfı,com.google.androidgamesdkpaketindenGameActivityöğesini genişletecek şekilde değiştirin:import com.google.androidgamesdk.GameActivity; public class YourGameActivity extends GameActivity { ... }Yerel kitaplığınızın, statik bir blok kullanılarak başlangıçta yüklendiğinden emin olun:
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"); } ... }Kitaplığınızın adı varsayılan ad (
libmain.so) değilseAndroidManifest.xml'a yerel kitaplığınızı ekleyin:<meta-data android:name="android.app.lib_name" android:value="android-game" />
android_main işlevini uygulama
android_native_app_gluekitaplığı, oyununuzun ana iş parçacığında engellemeyi önlemek içinGameActivityyaşam döngüsü etkinliklerini ayrı bir iş parçacığında yönetmek üzere kullandığı bir kaynak kodu kitaplığıdır. Kitaplığı kullanırken, dokunma girişi etkinlikleri gibi yaşam döngüsü etkinliklerini işlemek için geri çağırma işlevini kaydedersiniz.GameActivityarşivi,android_native_app_gluekitaplığının kendi sürümünü içerdiğinden NDK sürümlerinde yer alan sürümü kullanamazsınız. Oyunlarınız NDK'da bulunanandroid_native_app_gluekitaplığını kullanıyorsaGameActivitysürümüne geçin.android_native_app_gluekitaplığı kaynak kodunu projenize ekledikten sonraGameActivityile arayüz oluşturur. Kitaplık tarafından çağrılan ve oyununuzun giriş noktası olarak kullanılanandroid_mainadlı bir işlev uygulayın.android_appadlı bir yapı iletilir. Bu durum, oyununuza ve motorunuza göre farklılık gösterebilir. Örneğin:#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; }Ana oyun döngünüzde
android_appişlemini yapın. Örneğin, NativeAppGlueAppCmd içinde tanımlanan uygulama döngüsü etkinliklerini yoklayın ve işleyin. Örneğin, aşağıdaki snippet,_hand_cmd_proxyişleviniNativeAppGlueAppCmdişleyicisi olarak kaydeder, ardından uygulama döngüsü etkinliklerini yoklar ve işlenmek üzere kayıtlı işleyiciye(android_app::onAppCmdiçinde) gönderir: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(); } } }Daha fazla bilgi için Endless Tunnel NDK örneğinin uygulanmasını inceleyin. Buradaki temel fark, etkinliklerin nasıl ele alınacağıdır. Bu konu, sonraki bölümde açıklanmaktadır.
Etkinlikleri işleme
Giriş etkinliklerinin uygulamanıza ulaşmasını sağlamak için android_app_set_motion_event_filter ve android_app_set_key_event_filter ile etkinlik filtrelerinizi oluşturup kaydedin.
native_app_glue kitaplığı varsayılan olarak yalnızca SOURCE_TOUCHSCREEN girişinden gelen hareket etkinliklerine izin verir. Ayrıntılar için referans dokümanı ve android_native_app_glue uygulama kodunu inceleyin.
Giriş etkinliklerini işlemek için oyun döngünüzde android_input_buffer ile android_app_swap_input_buffers() kullanarak android_input_buffer öğesine referans alın. Bunlar, son yoklamadan bu yana gerçekleşen hareket etkinliklerini ve önemli etkinlikleri içerir. İçerilen etkinlik sayısı sırasıyla motionEventsCount ve keyEventsCount içinde saklanır.
Oyun döngünüzdeki her etkinliği yineleyin ve işleyin. Bu örnekte, aşağıdaki kod
motionEventsüzerinde yinelenir ve bunlarıhandle_eventaracılığıyla işler: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); }_cookEventForPointerIndex()ve diğer ilgili işlevlerin uygulanması için GitHub örneğine bakın.İşiniz bittiğinde, az önce işlediğiniz etkinlik kuyruğunu temizlemeyi unutmayın:
android_app_clear_motion_events(mApp);
Ek kaynaklar
GameActivity hakkında daha fazla bilgi edinmek için aşağıdakileri inceleyin:
- GameActivity ve AGDK sürüm notları.
- GameActivity'de GameTextInput'u kullanın.
- NativeActivity taşıma rehberi.
- GameActivity referans belgeleri.
- GameActivity uygulaması.
Hataları bildirmek veya GameActivity'ye yeni özellikler eklenmesini istemek için GameActivity sorun izleyicisini kullanın.