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, önemli 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, oyununuza giriş noktası olarak hizmet verir ve ayrıca çizim yapmak için Window sağlar. Birçok oyun, JNI kodunu kullanarak C veya C++ oyun kodlarına köprü oluştururken NativeActivity sınırlamalarını aşmak için bu Activity kendi Java veya Kotlin sınıflarıyla genişletir.
GameActivity aşağıdaki özellikleri sunar:
AppCompatActivityöğesinden devralır. Bu sayede Android Jetpack Architecture Components'ı kullanabilirsiniz.Diğer Android kullanıcı arayüzü öğeleriyle etkileşim kurmanıza olanak tanıyan bir
SurfaceViewolarak oluşturulur.Java etkinliklerini işler. Bu, 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'si 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 sürecinize 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 için 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 }- Prefabrik 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-activitystatik 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 bildirmeniz gerekir. Daha fazla bilgi için Etkinliklere Giriş başlıklı makaleyi inceleyin.
Android Manifesti
Her uygulama projesinin, proje kaynak kümesinin kök dizininde 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. Bu güvenlik özelliklerinden bazıları şunlardır:
Oyununuzu Google Play'de 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ık adınız varsayılan ad (
libmain.so) değilse yerel kitaplığınızıAndroidManifest.xml'a ekleyin:<meta-data android:name="android.app.lib_name" android:value="android-game" />
android_main öğesini 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ğırmayı 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ıya iletilir. Bu durum, oyununuza ve motorunuza göre farklılık gösterebilir. Aşağıda bununla ilgili bir örnek verilmiştir:#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 yoklama ve işleme. Ö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. Asıl fark, etkinliklerin nasıl ele alınacağıyla ilgili olacaktı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.
Varsayılan olarak, native_app_glue kitaplığı yalnızca SOURCE_TOUCHSCREEN girişinden gelen hareket etkinliklerine izin verir. Ayrıntılar için referans dokümanını 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() öğ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ı.
Hata bildirmek veya GameActivity'ye yeni özellikler istemek için GameActivity sorun izleyicisini kullanın.