ย้ายข้อมูลจาก NativeActivity ส่วนหนึ่งของ Android Game Development Kit
หน้านี้จะอธิบายวิธีย้ายข้อมูลจาก
NativeActivity
ไปยัง
GameActivity
ในโปรเจ็กต์เกม Android
GameActivity
อิงตาม NativeActivity
จากเฟรมเวิร์ก Android
โดยมีการเพิ่มประสิทธิภาพและฟีเจอร์ใหม่ๆ ดังนี้
- รองรับ
Fragment
จาก Jetpack - เพิ่มการรองรับ
TextInput
เพื่ออำนวยความสะดวกในการผสานรวมแป้นพิมพ์ซอฟต์แวร์ - จัดการเหตุการณ์การแตะและเหตุการณ์คีย์ใน
GameActivity
คลาส Java แทนNativeActivity
onInputEvent
อินเทอร์เฟซ
ก่อนย้ายข้อมูล เราขอแนะนำให้อ่านคู่มือการเริ่มต้นใช้งาน ซึ่งอธิบายวิธีตั้งค่าและผสานรวม GameActivity
ในโปรเจ็กต์
การอัปเดตสคริปต์บิลด์ Java
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 }
เพิ่มทรัพยากร Dependency ของ
GameActivity
ลงในแอปพลิเคชัน- เพิ่มไลบรารี
core
และgames-activity
- หากระดับ API ขั้นต่ำที่รองรับในปัจจุบันต่ำกว่า 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>
ดูวิธีการโดยละเอียดสำหรับโหมดเต็มหน้าจอได้ที่คำแนะนำเกี่ยวกับโหมดสมจริงและการติดตั้งใช้งานตัวอย่างในที่เก็บตัวอย่างเกม
คำแนะนำในการย้ายข้อมูลนี้จะไม่เปลี่ยนชื่อไลบรารีเนทีฟ หากคุณเปลี่ยน ชื่อ โปรดตรวจสอบว่าชื่อไลบรารีเนทีฟสอดคล้องกันในตำแหน่ง 3 แห่งต่อไปนี้
โค้ด 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 ขึ้นไป เราจะจัดจำหน่ายไลบรารีแบบคงที่ ไลบรารีแบบคงที่ เป็นประเภทการเผยแพร่ที่แนะนำ
โดยจะรวมรุ่นไว้ใน AAR พร้อมกับยูทิลิตี
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
prefab ดังนี้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_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; }
ตรวจสอบและอัปเดตตรรกะที่แนบมากับ NativeActivity
AInputEvent
ดังที่แสดงในขั้นตอนก่อนหน้าInputBuffer
การประมวลผลของ GameActivity จะอยู่นอกลูปALooper_pollOnce()
แทนที่การใช้งาน
android_app::activity->clazz
ด้วยandroid_app:: activity->javaGameActivity
GameActivity จะเปลี่ยนชื่ออินสแตนซ์GameActivity
ของ Java
ขั้นตอนเพิ่มเติม
ขั้นตอนก่อนหน้านี้ครอบคลุมฟังก์ชันการทำงานของ NativeActivity แต่ GameActivity
มี
ฟีเจอร์เพิ่มเติมที่คุณอาจต้องการใช้ ดังนี้
- TextInput
- เกมคอนโทรลเลอร์
- Fragment
- คำสั่ง InSets ของหน้าต่างใหม่ที่กำหนดไว้ใน NativeAppGlueAppCmd
เราขอแนะนำให้คุณลองใช้ฟีเจอร์เหล่านี้และนำไปใช้กับเกมของคุณตามความเหมาะสม
หากมีคำถามหรือคำแนะนำสำหรับ GameActivity หรือไลบรารี AGDK อื่นๆ โปรดสร้างข้อบกพร่องเพื่อแจ้งให้เราทราบ