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
SurfaceView
olarak oluşturulur.Java etkinliklerini işler. Bu, herhangi bir Android kullanıcı arayüzü öğesinin (ör.
EditText
,WebView
veyaAd
) C arayüzü üzerinden oyununuza entegre edilmesini sağlar.NativeActivity
veandroid_native_app_glue
kitaplığı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.
GameActivity
kitaplık 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 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ınandroid
bloğuna aşağıdakileri ekleyin:
buildFeatures { prefab true }
- Prefabrik sürümü seçin ve
gradle.properties
dosyasına ayarlayın:
android.prefabVersion=2.0.0
Daha 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.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ındagame-activity
paketini içe aktarın ve hedefinize ekleyin.game-activity
paketilibandroid.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
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ğ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.
GameActivity
veNativeActivity
iç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.xml
dosyanızdakiactivity
öğesinde belirtilen sınıf). Bu sınıfı,com.google.androidgamesdk
paketindenGameActivity
öğ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_glue
kitaplığı, oyununuzun ana iş parçacığında engellemeyi önlemek içinGameActivity
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 bulunanandroid_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ı 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; }
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ş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_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_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.İş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.