انتقال از NativeActivity بخشی از Android Game Development Kit.
این صفحه نحوه انتقال از
NativeActivity به
GameActivity را در پروژه بازی Android شما شرح میدهد.
GameActivity براساس NativeActivity از چارچوب Android است،
با بهبودها و ویژگیهای جدید:
- از
Fragmentاز Jetpack پشتیبانی میکند. - پشتیبانی
TextInputرا برای تسهیل ادغام صفحهکلید نرمافزاری اضافه میکند. - رویدادهای لمسی و کلیدی را در کلاس جاوا
GameActivityبهجای میانایNativeActivityonInputEventمدیریت میکند.
قبلاز انتقال، توصیه میکنیم
راهنمای شروع به کار را بخوانید که نحوه
راهاندازی و ادغام GameActivity را در پروژهتان شرح میدهد.
بهروزرسانیهای اسکریپت ساخت جاوا
GameActivity بهعنوان کتابخانه Jetpack توزیع میشود. حتماً مراحل بهروزرسانی اسکریپت Gradle را که در راهنمای شروع به کار شرح داده شده است اعمال کنید:
کتابخانه Jetpack را در فایل
gradle.propertiesپروژهتان فعال کنید:android.useAndroidX=trueدرصورت تمایل، نسخه Prefab را در همان فایل
gradle.propertiesمشخص کنید، برای مثال:android.prefabVersion=2.0.0ویژگی Prefab را در فایل
build.gradleبرنامهتان فعال کنید:android { ... // other configurations buildFeatures.prefab true }وابستگی
GameActivityرا به برنامهتان اضافه کنید:- کتابخانههای
coreوgames-activityرا اضافه کنید. - اگر حداقل سطح API پشتیبانیشده فعلی شما کمتر از ۱۶ است، آن را به حداقل ۱۶ بهروز کنید.
- نسخه کیت توسعه نرمافزار کامپایلشده را به نسخهای که کتابخانه
games-activityنیاز دارد بهروز کنید. Jetpack معمولاً به جدیدترین نسخه کیت توسعه نرمافزار در زمان ساخت نسخه پخش نیاز دارد.
فایل
build.gradleبهروزشده شما ممکن است چیزی شبیه این باشد:android { compiledSdkVersion 33 ... // other configurations. defaultConfig { minSdkVersion 16 } ... // other configurations. buildFeatures.prefab true } dependencies { implementation 'androidx.core:core:1.9.0' implementation 'androidx.games:games-activity:1.2.2' }- کتابخانههای
بهروزرسانیهای کد Kotlin یا Java
NativeActivity میتواند بهعنوان فعالیت راهاندازی استفاده شود و برنامهای تمامصفحه ایجاد میکند. درحالحاضر، GameActivity نمیتواند بهعنوان فعالیت راهاندازی استفاده شود. برنامهها باید کلاسی را از GameActivity مشتق کنند و از آن بهعنوان
فعالیت راهاندازی استفاده کنند. همچنین باید تغییرات پیکربندی بیشتری برای ایجاد برنامه تمامصفحه اعمال کنید.
مراحل زیر فرض میکند که برنامه شما از NativeActivity بهعنوان فعالیت راهاندازی استفاده میکند. اگر اینطور نیست، میتوانید از بیشتر آنها رد شوید.
یک فایل Kotlin یا Java برای میزبانی فعالیت راهاندازی جدید ایجاد کنید. برای مثال، کد زیر
MainActivityرا بهعنوان فعالیت راهاندازی ایجاد میکند و کتابخانه بومی اصلی برنامه،libAndroidGame.so، را بار میکند:کاتلین
class MainActivity : GameActivity() { override fun onResume() { super.onResume() // Use the function recommended from the following page: // https://d.android.com/training/system-ui/immersive hideSystemBars() } companion object { init { System.loadLibrary("AndroidGame") } } }
جاوا
public class MainActivity extends GameActivity { protected void onResume() { super.onResume(); // Use the function recommended from // https://d.android.com/training/system-ui/immersive hideSystemBars(); } static { System.loadLibrary("AndroidGame"); } }
در فایل
res\values\themes.xml، زمینه برنامه تمامصفحه ایجاد کنید:<resources xmlns:tools="http://schemas.android.com/tools"> <!-- Base application theme. --> <style name="Application.Fullscreen" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowFullscreen">true</item> <item name="android:windowContentOverlay">@null</item>" </style> </resources>زمینه را در فایل
AndroidManifest.xmlروی برنامه اعمال کنید:<application android:theme=”@style/Application.Fullscreen”> <!-- other configurations not listed here. --> </application>برای دستورالعملهای دقیق درباره حالت تمامصفحه، به راهنمای فراگیر و نمونه پیادهسازی در مخزن نمونههای بازی مراجعه کنید.
این راهنمای انتقال نام کتابخانه بومی را تغییر نمیدهد. اگر آن را تغییر دادید، مطمئن شوید نامهای کتابخانه بومی در سه مکان زیر یکسان باشد:
کد Kotlin یا Java:
System.loadLibrary(“AndroidGame”)AndroidManifest.xml:<meta-data android:name="android.app.lib_name" android:value="AndroidGame" />درون فایل اسکریپت ساخت C/C++، برای مثال
CMakeLists.txt:add_library(AndroidGame ...)
بهروزرسانیهای اسکریپت ساخت C/C++
دستورالعملهای این بخش از cmake بهعنوان نمونه استفاده میکند. اگر برنامهتان
از ndk-build استفاده میکند، باید آنها را به فرمانهای معادل شرحدادهشده در
صفحه اسناد ndk-build نگاشت کنید.
پیادهسازی C/C++ در GameActivity نسخه کد منبع را ارائه کرده است. برای نسخه ۱.۲.۲ و نسخههای جدیدتر، نسخه کتابخانه ایستا ارائه شده است. کتابخانه ایستا نوع انتشار توصیهشده است.
نسخه پخش با ابزار کمکی
prefab
درون AAR بستهبندی شده است. کد بومی شامل منابع C/C++ مربوط به GameActivity و کد
native_app_glue است. این کتابخانهها باید همراه با کد C/C++ برنامهتان ساخته شوند.
NativeActivity برنامه ازقبل از کد native_app_glue
ارسالشده در NDK استفاده میکنند. باید آن را با نسخه GameActivity
native_app_glue جایگزین کنید. بهجز این، همه مراحل cmake که در راهنمای شروع به کار مستند شده است اعمال میشود:
کتابخانه ثابت C/C++ یا کد منبع C/++ را بهصورت زیر به پروژهتان وارد کنید.
کتابخانه ایستا
در فایل
CMakeLists.txtپروژهتان، کتابخانه ایستاgame-activityرا به ماژول پیشساختهgame-activity_staticوارد کنید:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)کد منبع
در فایل
CMakeLists.txtپروژه، بستهgame-activityرا وارد کنید و آن را به هدف خود اضافه کنید. بستهgame-activityبهlibandroid.soنیاز دارد، بنابراین اگر وجود ندارد، باید آن را نیز وارد کنید.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)همه ارجاعها به کد
native_app_glueNDK را بردارید، مثل:${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ... set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")اگر از نسخه کد منبع استفاده میکنید، فایلهای منبع
GameActivityرا اضافه کنید. درغیراینصورت، از این مرحله رد شوید.get_target_property(game-activity-include game-activity::game-activity INTERFACE_INCLUDE_DIRECTORIES) add_library(${PROJECT_NAME} SHARED main.cpp ${game-activity-include}/game-activity/native_app_glue/android_native_app_glue.c ${game-activity-include}/game-activity/GameActivity.cpp ${game-activity-include}/game-text-input/gametextinput.cpp)
رفع مشکل UnsatisfiedLinkError
اگر با UnsatsifiedLinkError برای تابع
com.google.androidgamesdk.GameActivity.initializeNativeCode() مواجه شدید،
این کد را به فایل CMakeLists.txt اضافه کنید:
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u \
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")
بهروزرسانیهای کد منبع C/C++
برای جایگزین کردن ارجاعهای NativeActivity در برنامهتان با GameActivity، این مراحل را دنبال کنید:
از
native_app_glueمنتشرشده باGameActivityاستفاده کنید. جستجو کنید و همه موارد استفاده ازandroid_native_app_glue.hرا با این مورد جایگزین کنید:#include <game-activity/native_app_glue/android_native_app_glue.h>هم فیلتر رویداد حرکت و هم فیلتر رویداد کلیدی را روی
NULLتنظیم کنید تا برنامهتان بتواند رویدادهای ورودی را از همه دستگاههای ورودی دریافت کند. معمولاً این کار را در تابعandroid_main()انجام میدهید:void android_main(android_app* app) { ... // other init code. android_app_set_key_event_filter(app, NULL); android_app_set_motion_event_filter(app, NULL); ... // additional init code, and game loop code. }کد مربوط به
AInputEventرا بردارید و آن را با پیادهسازیInputBufferGameActivity جایگزین کنید:while (true) { // Read all pending events. int events; struct android_poll_source* source; // If not animating, block forever waiting for events. // If animating, loop until all events are read, then continue // to draw the next frame of animation. while ((ALooper_pollOnce(engine.animating ? 0 : -1, nullptr, &events, (void**)&source)) >= 0) { // Process this app cycle or inset change event. if (source) { source->process(source->app, source); } ... // Other processing. // Check if app is exiting. if (state->destroyRequested) { engine_term_display(&engine); return; } } // Process input events if there are any. engine_handle_input(state); if (engine.animating) { // Draw a game frame. } } // Implement input event handling function. static int32_t engine_handle_input(struct android_app* app) { auto* engine = (struct engine*)app->userData; auto ib = android_app_swap_input_buffers(app); if (ib && ib->motionEventsCount) { for (int i = 0; i < ib->motionEventsCount; i++) { auto *event = &ib->motionEvents[i]; int32_t ptrIdx = 0; switch (event->action & AMOTION_EVENT_ACTION_MASK) { case AMOTION_EVENT_ACTION_POINTER_DOWN: case AMOTION_EVENT_ACTION_POINTER_UP: // Retrieve the index for the starting and the ending of any secondary pointers ptrIdx = (event->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_UP: engine->state.x = GameActivityPointerAxes_getAxisValue( &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_X); engine->state.y = GameActivityPointerAxes_getAxisValue( &event->pointers[ptrIdx], AMOTION_EVENT_AXIS_Y); break; case AMOTION_EVENT_ACTION_MOVE: // Process the move action: the new coordinates for all active touch pointers // are inside the event->pointers[]. Compare with our internally saved // coordinates to find out which pointers are actually moved. Note that there is // no index embedded inside event->action for AMOTION_EVENT_ACTION_MOVE (there // might be multiple pointers moved at the same time). ... break; } } android_app_clear_motion_events(ib); } // Process the KeyEvent in a similar way. ... return 0; }منطق پیوستشده به
AInputEventNativeActivity را بازبینی و بهروز کنید. همانطور که در مرحله قبل نشان داده شد، پردازشInputBufferGameActivity خارج از حلقهALooper_pollOnce()است.استفاده از
android_app::activity->clazzرا باandroid_app:: activity->javaGameActivityجایگزین کنید. GameActivity نام نمونه JavaGameActivityرا تغییر میدهد.
مراحل بیشتر
مراحل قبلی عملکرد NativeActivity را پوشش میدهد، اما GameActivity
ویژگیهای دیگری دارد که ممکن است بخواهید از آنها استفاده کنید:
- TextInput.
- کنترل بازی.
- Fragment.
- فرمانهای InSets پنجره جدید در NativeAppGlueAppCmd تعریف شده است.
توصیه میکنیم این ویژگیها را کاوش کنید و آنها را بهطور مناسب برای بازیهایتان اتخاذ کنید.
اگر سؤال یا توصیهای برای GameActivity یا سایر کتابخانههای AGDK دارید، اشکالی ایجاد کنید تا به ما اطلاع دهید.