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:

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.

  1. GameActivity kitaplık bağımlılığını oyununuzun build.gradle dosyasına eklemek için Jetpack Android Games sayfasındaki talimatları uygulayın.

  2. 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.gradle dosyasının android bloğuna aşağıdakileri ekleyin:
    buildFeatures {
        prefab true
    }
    
    android.prefabVersion=2.0.0
    

    Daha eski AGP sürümlerini kullanıyorsanız ilgili yapılandırma talimatları için prefab belgelerini inceleyin.

  3. C/C++ statik kitaplığını veya C/++ kaynak kodunu projenize aşağıdaki şekilde aktarın.

    Statik kitaplık

    Projenizin CMakeLists.txt dosyasında, game-activity statik kitaplığını game-activity_static prefab 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.txt dosyasında game-activity paketini içe aktarın ve hedefinize ekleyin. game-activity paketi libandroid.so gerektirir. 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.txt bölümüne ekleyin: GameActivity.cpp, GameTextInput.cpp ve android_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:

Oyununuza GameActivity'yi uygulama

  1. Ana etkinlik Java sınıfınızı oluşturun veya tanımlayın (AndroidManifest.xml dosyanızdaki activity öğesinde belirtilen sınıf). Bu sınıfı, com.google.androidgamesdk paketinden GameActivity öğesini genişletecek şekilde değiştirin:

    import com.google.androidgamesdk.GameActivity;
    
    public class YourGameActivity extends GameActivity { ... }
    
  2. 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");
      }
      ...
    }
    
  3. 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

  1. android_native_app_glue kitaplığı, oyununuzun ana iş parçacığında engellemeyi önlemek için GameActivity yaş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. GameActivity arşivi, android_native_app_glue kitaplığı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 bulunan android_native_app_glue kitaplığını kullanıyorsa GameActivity sürümüne geçin.

    android_native_app_glue kitaplığı kaynak kodunu projenize ekledikten sonra GameActivity ile arayüz oluşturur. Kitaplık tarafından çağrılan ve oyununuzun giriş noktası olarak kullanılan android_main adlı bir işlev uygulayın. android_app adlı 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;
    }
    
  2. Ana oyun döngünüzde android_app iş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_proxy işlevini NativeAppGlueAppCmd işleyicisi olarak kaydeder, ardından uygulama döngüsü etkinliklerini yoklar ve işlenmek üzere kayıtlı işleyiciye(android_app::onAppCmd iç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();
        }
      }
    }
    
  3. 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.

  1. Oyun döngünüzdeki her etkinliği yineleyin ve işleyin. Bu örnekte, aşağıdaki kod motionEvents üzerinde yinelenir ve bunları handle_event aracı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.

  2. İş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:

Hata bildirmek veya GameActivity'ye yeni özellikler istemek için GameActivity sorun izleyicisini kullanın.