GameActivity'yi kullanmaya başlayın Android Oyun Geliştirme Kiti'nin bir parçasıdır.

Bu kılavuzda, kurulum ve entegrasyon işlemleri açıklanmaktadır. GameActivity ve Android cihazınızdaki etkinlikleri işleyin bir oyundur.

GameActivity, C veya kritik API'ları kullanma sürecini basitleştirerek Android'e C++ oyunu kazandırdı. Önceki NativeActivity: oyunlar için önerilen sınıf. GameActivity, bu yeri önerilen olarak değiştirir için geliştirilmiştir ve API düzeyi 19'a kadar geriye dönük uyumludur.

GameActivity'yi entegre eden bir örnek için şuraya bakın: oyun örnekleri deposu'na gidin.

Başlamadan önce

Şu dillere ait GameActivity sürüme göz atın: bir dağılım elde edersiniz.

Derlemenizi ayarlayın

Android'de giriş olarak Activity kullanılır sağlar ve aynı zamanda kullanıcılara Çizim için Window. Birçok oyun sınırlamaları aşmak için kendi Java veya Kotlin sınıfıyla bu Activity Köprü için JNI kodu kullanılırken NativeActivity C veya C++ oyun kodlarına ekliyorlar.

GameActivity aşağıdaki özellikleri sunar:

GameActivity, Android Arşivi olarak dağıtılır (AAR). Bu AAR, şunu içeren Java sınıfını içerir: anahtar kelime olarak AndroidManifest.xml ve C ve GameActivity ürününün Java tarafını uygulamanın C/C++ uygulaması. GameActivity 1.2.2 veya daha yeni bir sürüm kullanıyorsanız C/C++ statik kitaplık da sağlanır. Geçerli olduğu durumlarda kaynak kodu yerine statik kitaplıktan yararlanır.

Bu kaynak dosyaları veya statik kitaplığı DMAIC ve Yalın Altı Sigma yaklaşımı Prefab Böylece, yerel kitaplıkları ve kaynak kodunu CMake project veya NDK derlemesi.

  1. Şu adresteki talimatları uygulayın: Jetpack Android Games sayfasında Oyununuzun build.gradle dosyasına GameActivity kitaplık bağımlılığı.

  2. Aşağıdakileri şununla yaparak prefab'i etkinleştirin: Android Eklenti Sürümü (AGP) 4.1+:

    • Aşağıdakini, modülünüzün build.gradle dosyasının android bloğuna ekleyin:
    buildFeatures {
        prefab true
    }
    
    android.prefabVersion=2.0.0
    

    Önceki AGP sürümlerini kullanıyorsanız prefab belgelerine göz atın sayfasına bakın.

  3. C/C++ statik kitaplığını veya C/++ kaynak kodunu takip etmeniz gerekir.

    Statik kitaplık

    Projenizin CMakeLists.txt dosyasına game-activity statik game-activity_static prefab modülüne ekledik:

    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ına game-activity pakete ekleyip hedefinize ekleyin. game-activity paketi için gerekenler libandroid.so; eksikse dosyayı da içe aktarmanız gerekir.

    find_package(game-activity REQUIRED CONFIG)
    ...
    target_link_libraries(... android game-activity::game-activity)
    

    Ayrıca projenizin CmakeLists.txt dosyasına aşağıdaki dosyaları da ekleyin: GameActivity.cpp, GameTextInput.cpp ve android_native_app_glue.c.

Android, Etkinliğinizi nasıl başlatır?

Android sistemi, geri çağırma işlemini çağırarak Etkinlik örneğinizde kodu yürütür belirli aşamalara karşılık gelen yöntemlerle ilişkilendirilir. Siparişte uygulamanızı başlatması için izin vermeniz durumunda, Android Manifest'te uygun özelliklerle yapmanızı öneririz. Daha fazla bkz. Etkinliklere Giriş.

Android Manifesti

Her uygulama projesinin AndroidManifest.xml dosyasını kökünü oluşturur. Manifest dosyası, Android derleme araçları, Android işletim sistemi ve sistemi ve Google Play. Bu güvenlik özelliklerinden bazıları şunlardır:

Oyununuzda GameActivity'yi uygulayın

  1. Ana etkinlik Java sınıfınızı ( activity öğesi AndroidManifest.xml dosyanızın içinde bulunur). Bu sınıfı şu şekilde değiştir: com.google.androidgamesdk paketinden GameActivity uzat:

    import com.google.androidgamesdk.GameActivity;
    
    public class YourGameActivity extends GameActivity { ... }
    
  2. Yerel kitaplığınızın başlangıçta statik blok kullanarak 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. Yerel kitaplığınızı AndroidManifest.xml'e ekleme kitaplığınızın adı varsayılan ad (libmain.so) değilse:

    <meta-data android:name="android.app.lib_name"
     android:value="android-game" />
    

android_main uygulama

  1. android_native_app_glue kitaplığı, GameActivity yaşam döngüsü olaylarını ayrı bir iş parçacığında yönetmek için engellemek için Search Ads 360'ı kullanın. Kitaplığı kullanırken Dokunmatik giriş gibi yaşam döngüsü olaylarını işlemek için geri çağırmayı kaydedersiniz etkinlikler. GameActivity arşivi kendi sürümünü içerir android_native_app_glue kitaplığı için mevcut sürümü kullanamazsınız NDK sürümleri. Oyunlarınız android_native_app_glue kitaplığını kullanıyorsa GameActivity sürümüne geçin.

    android_native_app_glue kitaplığı kaynak kodunu GameActivity ile arayüz oluşturur. Şu ada sahip bir fonksiyonu uygulayın: android_main, başlangıç noktası olarak kullanılır. Geçen yıl android_app adlı yapıyı oluşturur. Bu, oyununuza ve motorunuza göre değişiklik 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. android_app işlemini ana oyun döngünüzde (ör. yoklama ve yürütme) işleyin. NativeAppGlueAppCmd'de tanımlanan uygulama döngüsü etkinlikleri. Örneğin, aşağıdaki snippet _hand_cmd_proxy işlevini NativeAppGlueAppCmd işleyicisi, daha sonra uygulama döngüsü etkinliklerini yoklar ve bunları işleme için kayıtlı işleyici(android_app::onAppCmd dilinde):

    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();
        }
      }
    }
    
  3. Daha fazla bilgi edinmek için Sonsuz Tünel'in nasıl uygulandığını inceleyin NDK örneği. Temel fark, etkinliklerin aşağıda gösterildiği gibi nasıl işleneceğidir: ele alacağız.

Etkinlikleri yönetme

Giriş etkinliklerinin uygulamanıza ulaşmasını etkinleştirmek için etkinliğinizi oluşturup kaydedin android_app_set_motion_event_filter içeren filtreler ve android_app_set_key_event_filter. Varsayılan olarak native_app_glue kitaplığı yalnızca şu kameralardaki hareket etkinliklerine izin verir: KAYNAK_DOKUNMA EKRANI giriş. Referans belgeyi incelemeyi unutmayın. ve android_native_app_glue uygulama koduna bakın.

Giriş etkinliklerini işlemek için şunu içeren bir android_input_buffer referansı alın: android_app_swap_input_buffers() her bir görev için geçerlidir. Bunlar, en son gerçekleştirildiği zamandan bu yana gerçekleşen hareket etkinliklerini ve önemli etkinlikleri içerir. anket yapıldı. İçerdiği etkinliklerin sayısı motionEventsCount içinde depolanır ve Sırasıyla keyEventsCount.

  1. Oyun döngünüzdeki her etkinliği yineleyin ve yönetin. Bu örnekte aşağıdaki kod motionEvents işlemini yineler ve bunları handle_event üzerinden 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);
    }
    

    Bkz. GitHub örneği _cookEventForPointerIndex() ve diğer özelliklerin uygulanması için benzer işlevler sunar.

  2. İşiniz bittiğinde, az önce tamamladığınız etkinlik sırasını temizlemeyi işlenen:

    android_app_clear_motion_events(mApp);
    

Ek kaynaklar

GameActivity hakkında daha fazla bilgi edinmek için aşağıdakilere göz atın:

Hataları bildirmek veya GameActivity'ye yeni özellikler eklemek için GameActivity Sorun İzleyici'yi kullanın.