Di chuyển từ NativeActivity Một phần của Android Game Development Kit.
Trang này mô tả cách di chuyển từ
NativeActivity sang
GameActivity trong dự án trò chơi Android của bạn.
GameActivity dựa trên NativeActivity trong khung Android với các tính năng nâng cao mới:
- Hỗ trợ
Fragmenttừ Jetpack. - Thêm tuỳ chọn hỗ trợ
TextInputđể hỗ trợ tích hợp bàn phím mềm. - Xử lý các sự kiện chạm và sự kiện chính trong lớp Java
GameActivitythay vì giao diệnNativeActivityonInputEvent.
Trước khi di chuyển, bạn nên đọc hướng dẫn bắt đầu sử dụng. Hướng dẫn này mô tả cách thiết lập và tích hợp GameActivity vào dự án của bạn.
Cập nhật tập lệnh bản dựng Java
GameActivity được phân phối dưới dạng một thư viện Jetpack. Hãy nhớ áp dụng tập lệnh Gradle để cập nhật các bước như mô tả
trong hướng dẫn bắt đầu sử dụng:
Bật thư viện Jetpack trong tệp
gradle.propertiescủa dự án:android.useAndroidX=trueNếu muốn, bạn có thể chỉ định một phiên bản Prefab, trong cùng một tệp
gradle.properties, ví dụ:android.prefabVersion=2.0.0Bật tính năng Prefab trong tệp
build.gradlecủa ứng dụng:android { ... // other configurations buildFeatures.prefab true }Thêm phần phụ thuộc
GameActivityvào ứng dụng của bạn:- Thêm thư viện
corevàgames-activity. - Nếu hiện tại, cấp độ API tối thiểu được hỗ trợ của bạn là dưới 16, hãy cập nhật lên ít nhất là 16.
- Cập nhật phiên bản SDK đã biên dịch lên phiên bản mà thư viện
games-activityyêu cầu. Jetpack thường yêu cầu phiên bản SDK mới nhất tại thời điểm tạo bản phát hành.
Tệp
build.gradlemới cập nhật của bạn có thể trông như sau: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' }- Thêm thư viện
Cập nhật mã Kotlin hoặc Java
NativeActivity có thể được dùng làm hoạt động khởi động và tạo ứng dụng
toàn màn hình. Hiện tại, GameActivity không thể được sử dụng làm hoạt động
khởi động. Các ứng dụng phải lấy một lớp từ GameActivity và sử dụng lớp đó làm
hoạt động khởi động. Bạn cũng phải thực hiện các thay đổi khác đối với cấu hình để
tạo ứng dụng toàn màn hình.
Các bước sau đây giả định ứng dụng của bạn sử dụng NativeActivity làm hoạt động
khởi động. Nếu trường hợp này không xảy ra, bạn có thể bỏ qua hầu hết các trường hợp.
Tạo một tệp trong Kotlin hoặc Java để lưu trữ hoạt động khởi động mới. Ví dụ: mã sau đây tạo
MainActivitylàm hoạt động khởi động và tải thư viện gốc chính của ứng dụng,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"); } }
Tạo giao diện toàn ứng dụng ở chế độ toàn màn hình trong tệp
res\values\themes.xml:<resources xmlns:tools="http://schemas.android.com/t>ools&<quot; !-- Base application> them<e. -- style name="Application.Fullscreen" parent="Theme.App>Compat.Li<ght.NoActionBar" item n>ame=<">;android:<windowFullscreen"true/item >item <name=>"<androi>d<:windowCon>tentOverlay"@null/item" /style /resourcesÁp dụng giao diện cho ứng dụng trong tệp
AndroidManifest.xml:<application android:theme=”@style/Application.Fullscreen”> <!-- other configurations not listed here. --> </application>Để nắm được hướng dẫn chi tiết về chế độ toàn màn hình, hãy tham khảo hướng dẫn về chế độ sống động và ví dụ về cách triển khai trong kho lưu trữ mẫu trò chơi.
Hướng dẫn di chuyển này không thay đổi tên thư viện gốc. Nếu bạn thay đổi tên đó, hãy đảm bảo tên của các thư viện gốc nhất quán ở ba vị trí sau:
Mã Kotlin hoặc Java:
System.loadLibrary(“AndroidGame”)AndroidManifest.xml:<meta-data android:name="android.app.lib_name" android:value=">;AndroidGame" /Bên trong tệp tập lệnh bản dựng C/C++, ví dụ:
CMakeLists.txtadd_library(AndroidGame ...)
C/C++ tạo bản cập nhật tập lệnh
Các hướng dẫn trong phần này sử dụng cmake làm ví dụ. Nếu ứng dụng của bạn
sử dụng ndk-build, bạn cần liên kết các ứng dụng đó với các lệnh tương đương được mô tả trong
trang tài liệu về ndk-build.
Việc triển khai C/C++ của GameActivity đã cung cấp một bản phát hành mã nguồn. Đối với phiên bản 1.2.2 trở lên, hệ thống sẽ cung cấp một bản phát hành thư viện tĩnh. Thư viện tĩnh là loại bản phát hành được đề xuất.
Bản phát hành này được đóng gói trong AAR cùng với tiện ích prefab. Mã gốc bao gồm các nguồn C/C++ của GameActivity và mã
native_app_glue. Các mã này cần được xây dựng cùng với
mã C/C++ của ứng dụng.
Các ứng dụng NativeActivity đã sử dụng mã native_app_glue
được vận chuyển bên trong NDK. Bạn phải thay thế điều này bằng phiên bản native_app_glue của GameActivity. Ngoài ra, tất cả các bước cmake có trong tài liệu hướng dẫn bắt đầu này đều được áp dụng:
Nhập thư viện tĩnh C/C++ hoặc mã nguồn C/++ vào dự án của bạn theo cách dưới đây.
Thư viện tĩnh
Trong tệp
CMakeLists.txtcủa dự án, hãy nhập thư viện tĩnhgame-activityvào mô-đun prefabgame-activity_static:find_package(game-activity REQUIRED CONFIG) target_link_libraries(${PROJECT_NAME} PUBLIC log android game-activity::game-activity_static)Mã nguồn
Trong tệp
CMakeLists.txtcủa dự án, hãy nhập góigame-activityvà thêm gói đó vào mục tiêu của bạn. Góigame-activityyêu cầulibandroid.so, vì vậy nếu còn thiếu, bạn cũng phải nhập gói này.find_package(game-activity REQUIRED CONFIG) ... target_link_libraries(... android game-activity::game-activity)Xóa tất cả thông tin tham chiếu đến mã
native_app_gluecủa NDK, chẳng hạn như:${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c ... set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -u ANativeActivity_onCreate")Nếu bạn đang dùng bản phát hành mã nguồn, hãy thêm các tệp nguồn
GameActivity. Nếu không, hãy bỏ qua bước này.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)
Khắc phục lỗi UnsatisfiedLinkError
Nếu bạn gặp UnsatsifiedLinkError cho hàm com.google.androidgamesdk.GameActivity.initializeNativeCode(), hãy thêm mã này vào tệp CMakeLists.txt:
set(CMAKE_SHARED_LINKER_FLAGS
"${CMAKE_SHARED_LINKER_FLAGS} -u \
Java_com_google_androidgamesdk_GameActivity_initializeNativeCode")
Cập nhật mã nguồn C/C++
Làm theo các bước sau để thay thế các tệp tham chiếu NativeActivity trong
ứng dụng của bạn bằng GameActivity:
Sử dụng
native_app_glueđược phát hành vớiGameActivity. Tìm kiếm và thay thế mọi hoạt động sử dụngandroid_native_app_glue.hthành:#include <game-activity/native_app_glue/android_native_app_glue.h>Đặt cả bộ lọc sự kiện chuyển động lẫn bộ lọc sự kiện chính thành giá trị
NULLđể ứng dụng của bạn có thể nhận các sự kiện đầu vào từ mọi thiết bị đầu vào. Thông thường, bạn sẽ phải thực hiện việc này bên trong hàmandroid_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. }Xóa mã liên quan đến
AInputEventvà thay thế mã đó bằng cách triển khaiInputBuffercủa 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; }Xem lại và cập nhật logic được liên kết với
AInputEventcủa NativeActivity. Như đã thấy trong bước trước, quá trình xử lýInputBuffercủa GameActivity nằm ngoài vòng lặpALooper_pollOnce().Thay thế mức sử dụng
android_app::activity->clazzbằngandroid_app:: activity->javaGameActivity. GameActivity đổi tên bản sao JavaGameActivity.
Các bước bổ sung
Các bước trước có tính đến cả chức năng của NativeActivity, nhưng GameActivity có các tính năng bổ sung mà bạn có thể muốn sử dụng:
- TextInput.
- Game Controller.
- Fragment.
- Các lệnh InSet cửa sổ mới được xác định trong NativeAppGlueAppCmd.
Bạn nên khám phá và sử dụng những tính năng này cho phù hợp với trò chơi của mình.
Nếu bạn có thắc mắc hoặc đề xuất về GameActivity hoặc thư viện AGDK khác, hãy tạo lỗi để báo cho chúng tôi.