نقل البيانات من NativeActivity جزء من حزمة تطوير ألعاب Android.
توضّح هذه الصفحة كيفية نقل البيانات من
NativeActivity
إلى
GameActivity
في مشروع لعبة Android.
يستند GameActivity
إلى NativeActivity
من إطار عمل
Android، مع التحسينات والميزات الجديدة:
- يمكن استخدام
Fragment
من Jetpack. - إضافة دعم
TextInput
لتسهيل دمج لوحة المفاتيح اللينة. - لمعالجة أحداث اللمس والأحداث الرئيسية في فئة Java
GameActivity
بدلاً من واجهةNativeActivity
onInputEvent
.
قبل نقل البيانات، ننصحك بقراءة دليل البدء الذي يصف كيفية إعداد GameActivity
ودمجه في مشروعك.
تحديثات النصوص البرمجية لإصدار JavaScript
يتم توزيع حزمة "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
. - إذا كان الحد الأدنى الحالي لمستوى واجهة برمجة التطبيقات المتوافق أقل من 16، عليك تحديثه إلى 16 على الأقل.
- عليك تحديث إصدار حزمة تطوير البرامج (SDK) المجمّع إلى الإصدار الذي تتطلبه مكتبة
games-activity
. يتطلّب Jetpack عادةً أحدث إصدار من حزمة SDK في وقت إصدار الإصدار.
قد يبدو ملف
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
:Kotlin
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") } } }
Java
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 إمكانية إصدار رمز المصدر. بالنسبة إلى الإصدار 1.2.2 والإصدارات الأحدث، يتم توفير إصدار مكتبة ثابتة. المكتبة الثابتة هي نوع الإصدار الموصى به.
تتم تعبئة الإصدار داخل ميزة "الاقتراحات المطبّقة تلقائيًا" مع
أداة prefab
. يتضمن الرمز الأصلي مصادر C/C++ من GameActivity ورمز native_app_glue
. يجب إنشاؤها جنبًا إلى جنب مع
رمز C/C++ للتطبيق الخاص بك.
تستخدم NativeActivity
تطبيقات رمز native_app_glue
الذي تم شحنه داخل NDK. عليك استبداله بإصدار native_app_glue
من GameActivity. وبخلاف ذلك، تنطبق جميع الخطوات البالغ عددها 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_glue
الخاص بـ NDK، مثل:${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
واستبدله بتنفيذInputBuffer
في GameActivity: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_pollAll(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; }
راجِع وعدِّل المنطق المرفق بـ
AInputEvent
الخاص بـ NativeActivity. كما هو موضّح في الخطوة السابقة، لا تتم معالجةInputBuffer
في GameActivity في حلقةALooper_pollAll()
.يمكنك استبدال استخدام
android_app::activity->clazz
بـandroid_app:: activity->javaGameActivity
. يعيد GameActivity تسمية مثيل JavaGameActivity
.
خطوات إضافية
تتناول الخطوات السابقة وظائف NativeActivity، ولكن يتضمن GameActivity
ميزات إضافية قد ترغب في استخدامها:
- TextInput.
- وحدة تحكُّم في الألعاب:
- جزء.
- أوامر InSets نافذة جديدة تم تحديدها في NativeAppGlueAppCmd.
ننصحك باستكشاف هذه الميزات واستخدامها بما يناسب ألعابك.
إذا كان لديك أي أسئلة أو اقتراحات بشأن GameActivity أو مكتبات AGDK الأخرى، يُرجى إنشاء خطأ لإعلامنا بذلك.