GameActivity'yi kullanmaya başlayın Android Game Development Kit'in bir parçası.
Bu kılavuzda, GameActivity
'i nasıl kurup entegre edeceğiniz ve Android oyununuzdaki etkinlikleri nasıl yöneteceğiniz açıklanmaktadır.
GameActivity
, kritik API'leri kullanma sürecini basitleştirerek C veya C++ oyununuzu Android'e taşımanıza yardımcı olur.
Önceden NativeActivity
oyunlar için önerilen sınıftı. GameActivity
, oyunlar için önerilen sınıfın yerini alır ve API düzeyi 19 ile geriye dönük uyumludur.
GameActivity'nin entegre edildiği bir örnek için games-samples deposuna bakın.
Başlamadan önce
Dağıtım almak için GameActivity
sürümlerini inceleyin.
Derlemenizi ayarlama
Android'de, Activity
, oyununuz için giriş noktası görevi görür ve içinde çizim yapmak üzere
Window
olanağı sağlar. Birçok oyun, C veya C++ oyun kodlarına geçiş yapmak için JNI
kodunu kullanırken NativeActivity
oyunundaki 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
kaynağından devralarak Android Jetpack Mimari Bileşenleri'ni kullanmanıza olanak tanır.Diğer Android kullanıcı arayüzü öğeleriyle arayüz oluşturmanıza olanak tanıyan bir
SurfaceView
oluşturur.Java etkinliği etkinliklerini işler. Bu, herhangi bir Android kullanıcı arayüzü öğesinin (ör.
EditText
,WebView
veyaAd
) C arayüzü üzerinden oyununuza entegre edilmesine olanak tanır.NativeActivity
veandroid_native_app_glue
kitaplığına benzer bir C API sunar.
GameActivity
, 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 daha yeni bir sürüm kullanıyorsanız C/C++ statik kitaplığı da sağlanır. Uygun durumlarda, kaynak kodu yerine statik kitaplığı kullanmanızı öneririz.
Bu kaynak dosyaları veya statik kitaplığı, Prefab
aracılığıyla derleme sürecinizin bir parçası olarak dahil edin. Bu işlem, yerel kitaplıkları ve kaynak kodunu CMake projenize veya NDK derlemenize gösterir.
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ğıdakileri yaparak prefab'i etkinleştirin:
- Modülünüzün
build.gradle
dosyasınınandroid
bloğuna aşağıdakileri ekleyin:
buildFeatures { prefab true }
- Bir Prefab 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 dokümanlarındaki 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ındagame-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
paketi içinlibandroid.so
gerekir. Bu nedenle, bu paket yoksa içe aktarmanız gerekir.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)
Ayrıca şu dosyaları da 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ğinizde kod çalıştırır. Android'in etkinliğinizi başlatabilmesi ve oyununuzu başlatabilmesi için Android Manifest'te uygun özelliklerle etkinliğinizi bildirmeniz 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. Bunu başarmak için şunlardan yararlanırız:
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ş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 olarak libmain.so'dur).
Oyununuzda GameActivity'yi uygulama
Ana etkinlik Java sınıfınızı (
AndroidManifest.xml
dosyanızın içindekiactivity
öğesinde belirtilen) oluşturun veya tanımlayın.GameActivity
sınıfınıcom.google.androidgamesdk
paketinden 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 geri çağırmayı, dokunmatik giriş etkinlikleri gibi yaşam döngüsü olaylarını işlemek için kaydedersiniz.GameActivity
arşivindeandroid_native_app_glue
kitaplığının kendi sürümü yer alır. Bu nedenle NDK sürümlerindeki 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şlevi uygulayın.android_app
adlı bir yapıdan geçer. Bu, oyununuz ve motorunuz için 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; }
android_app
işlemini ana oyun döngünüzde yapın. Örneğin, NativeAppGlueAppCmd'de tanımlanan uygulama döngüsü etkinliklerini yoklama ve işleme. Örneğin, aşağıdaki snippet_hand_cmd_proxy
işleviniNativeAppGlueAppCmd
işleyici olarak kaydeder, ardından uygulama döngüsü etkinliklerini sorgular 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, bir sonraki bölümde gösterildiği gibi etkinliklerin nasıl ele alınacağıdı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 koduna göz atın.
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
bölümlerinde depolanır.
Oyun döngünüzdeki her etkinliği yineleyin ve yönetin. Bu örnekte, aşağıdaki kod
motionEvents
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 gerçekleştirdiğiniz etkinlikler sırasını temizlemeyi unutmayın:
android_app_clear_motion_events(mApp);
Ek kaynaklar
GameActivity
hakkında daha fazla bilgi edinmek 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 hataları bildirmek veya yeni özellikler isteğinde bulunmak için GameActivity sorun izleyicisini kullanın.