GameActivity'yi kullanmaya başlayın Android Game Development Kit'in bir parçasıdır.
Bu kılavuzda GameActivity
kurulumu, entegrasyonu ve Android oyununuzdaki etkinliklerin nasıl yönetileceği 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 NativeActivity
, oyunlar için önerilen sınıftı. GameActivity
, bu sınıfı oyunlar için önerilen sınıf olarak değiştirir ve API düzeyi 19 ile geriye dönük olarak uyumludur.
GameActivity'nin entegre edildiği bir örnek için oyun-örnekleri deposuna bakın.
Başlamadan önce
Dağıtım edinmek için GameActivity
sürüme göz atın.
Derlemenizi ayarlama
Android'de Activity
, oyununuz için giriş noktası olarak kullanılır ve içinde çizim yapabileceğiniz Window
görevi de görür. Birçok oyun, C veya C++ oyun kodlarına geçiş yapmak için JNI
kodunu kullanırken NativeActivity
ile ilgili sınırlamaları ortadan kaldırmak için bu Activity
oyununu kendi Java veya Kotlin sınıfıyla genişletir.
GameActivity
aşağıdaki özellikleri sunar:
AppCompatActivity
öğesinden devralır. Böylece Android Jetpack Architecture Bileşenleri'ni kullanabilirsiniz.Diğer Android kullanıcı arayüzü öğeleriyle etkileşim kurmanıza olanak tanıyan bir
SurfaceView
oluşturur.Java etkinliği etkinliklerini işler. Bu, herhangi bir Android kullanıcı arayüzü öğesinin (
EditText
,WebView
veyaAd
gibi) bir C arayüzü aracılığıyla oyununuza entegre edilmesine olanak tanır.NativeActivity
veandroid_native_app_glue
kitaplığına benzer bir C API sunar.
GameActivity
bir Android Arşivi (AAR) olarak dağıtılır. Bu AAR, AndroidManifest.xml
uygulamanızda kullandığınız Java sınıfının yanı sıra GameActivity
uygulamasını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ünü kullanıyorsanız C/C++ statik kitaplığı da sağlanır. Uygun olduğunda, kaynak kodu yerine statik kitaplığı kullanmanızı öneririz.
Bu kaynak dosyalarını veya statik kitaplığı, yerel kitaplıkları ve kaynak kodunu CMake projenize ya da NDK derlemenize sunan Prefab
aracılığıyla derleme işleminizin bir parçası olarak dahil edin.
GameActivity
kitaplığı bağımlılığını oyununuzunbuild.gradle
dosyasına eklemek için Jetpack Android Games sayfasındaki talimatları uygulayın.Android Plugin Version (AGP) 4.1+ ile aşağıdaki adımları uygulayarak prefab'i etkinleştirin:
- Modülünüzün
build.gradle
dosyasındakiandroid
bloğuna aşağıdaki kodu ekleyin:
buildFeatures { prefab true }
- Bir Prefab sürümü seçin ve
gradle.properties
dosyasına ayarlayın:
android.prefabVersion=2.0.0
Önceki AGP sürümlerini kullanıyorsanız ilgili yapılandırma talimatları için prefab belgelerindeki talimatları uygulayın.
- Modülünüzün
Projenize aşağıdaki gibi C/C++ statik kitaplığını veya C/++ kaynak kodunu içe aktarın.
Statik kitaplık
Projenizin
CMakeLists.txt
dosyasındakigame-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ınagame-activity
paketini içe aktarın ve hedefinize ekleyin.game-activity
paketi içinlibandroid.so
gerekir. Bu nedenle, eksikse paketi içe aktarmanız gerekir.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)
Ayrıca şu dosyaları projenizin
CmakeLists.txt
öğesine ekleyin:GameActivity.cpp
,GameTextInput.cpp
veandroid_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ğinizde kod çalıştırır. Android'in etkinliğinizi başlatabilmesi ve oyununuzu başlatabilmesi için etkinliğinizi Android Manifest'te uygun özelliklerle beyan etmeniz gerekir. Daha fazla bilgi için Etkinliklere Giriş bölümünü inceleyin.
Android Manifesti
Her uygulama projesinin, proje kaynağı kümesinin kök dizininde bir AndroidManifest.xml dosyası olmalıdır. Manifest dosyası, uygulamanızla ilgili temel bilgileri Android derleme araçlarına, Android işletim sistemine ve Google Play'e açıklar. Bu hizmet ve özellikler arasında aşağıdakiler bulunmaktadır:
Oyununuzu Google Play'de benzersiz bir ş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 korunan bölümlerine veya diğer uygulamalara erişim izinleri.
Oyununuzun donanım ve yazılım gereksinimlerini belirtmek için cihaz uyumluluğu.
GameActivity
veNativeActivity
için yerel kitaplık adı(libmain.so).
Oyununuzda GameActivity'yi uygulayın
Ana etkinlik Java sınıfınızı (
AndroidManifest.xml
dosyanızın içindekiactivity
öğesinde belirtilen) oluşturun veya tanımlayın.com.google.androidgamesdk
paketindenGameActivity
öğesini genişletmek için bu sınıfı değiştirin:import com.google.androidgamesdk.GameActivity; public class YourGameActivity extends GameActivity { ... }
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"); } ... }
Kitaplığınızın adı varsayılan ad (
libmain.so
) değilse yerel kitaplığınızıAndroidManifest.xml
'e ekleyin:<meta-data android:name="android.app.lib_name" android:value="android-game" />
android_main'i uygulama
android_native_app_glue
kitaplığı, oyununuzun ana iş parçacığınızda engellemeyi önlemek amacıylaGameActivity
yaşam döngüsü etkinliklerini ayrı bir iş parçacığında yönetmek için kullandığı bir kaynak kodu kitaplığıdır. Kitaplığı kullanırken, dokunmatik giriş etkinlikleri gibi yaşam döngüsü olaylarını işlemek için geri çağırmayı kaydedersiniz.GameActivity
arşivindeandroid_native_app_glue
kitaplığının kendi sürümü bulunduğundan NDK sürümlerine dahil olan sürümü kullanamazsınız. Oyunlarınız NDK'nın içerdiğiandroid_native_app_glue
kitaplığını kullanıyorsaGameActivity
sürümüne geçin.android_native_app_glue
kitaplığı kaynak kodunu projenize ekledikten sonraGameActivity
ile arayüz oluşturur. Kitaplık tarafından çağrılan ve oyununuzun giriş noktası olarak kullanılanandroid_main
adlı işlevi uygulayın.android_app
adlı bir yapıdan geçmiştir. Bu durum, oyununuz ve motorunuz için farklı olabilir. 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üzdeki
android_app
işlemini yapın. Örneğin, NativeAppGlueAppCmd öğesinde tanımlanan uygulama döngüsü etkinliklerini yoklama ve işleme. Örneğin, aşağıdaki snippet_hand_cmd_proxy
işleviniNativeAppGlueAppCmd
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_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(); } } }
Daha fazla okumak için Sonsuz Tünel NDK örneğinin uygulanmasını inceleyin. Temel fark, etkinliklerin bir sonraki bölümde gösterildiği gibi nasıl işleneceği olacaktır.
Etkinlikleri işleme
Giriş etkinliklerinin uygulamanıza ulaşmasını sağlamak için etkinlik filtrelerinizi android_app_set_motion_event_filter
ve android_app_set_key_event_filter
ile 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ı ve android_native_app_glue
uygulama kodunu mutlaka inceleyin.
Giriş etkinliklerini işlemek için oyun döngünüzde android_app_swap_input_buffers()
ile android_input_buffer
referansı alın. Bunlar, son anketten sonra gerçekleşen hareket etkinliklerini ve önemli etkinlikleri içerir. İçerilen etkinliklerin sayısı sırasıyla motionEventsCount
ve keyEventsCount
içinde depolanır.
Oyun döngünüzdeki her etkinliği yineleyin ve yönetin. Bu örnekte, aşağıdaki kod
motionEvents
iterasyonunu tekrarlar 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 ilgili diğer işlevlerin uygulanması için GitHub örneğine göz atın.İşiniz bittiğinde, az önce işlediğiniz etkinlikler sırasını temizlemeyi unutmayın:
android_app_clear_motion_events(mApp);
Ek kaynaklar
GameActivity
hakkında daha fazla bilgi için aşağıdakilere bakın:
- GameActivity ve AGDK sürüm notları.
- GameActivity'de GameTextInput'u kullanın.
- NativeActivity taşıma kılavuzu.
- GameActivity referans dokümanları.
- GameActivity kullanımı.
GameActivity'ye hata bildirmek veya yeni özellikler isteğinde bulunmak için GameActivity sorun izleyiciyi kullanın.