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ợ
Fragment
từ 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
GameActivity
thay vì giao diệnNativeActivity
onInputEvent
.
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.properties
của dự án:android.useAndroidX=true
Nế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.0
Bật tính năng Prefab trong tệp
build.gradle
của ứng dụng:android { ... // other configurations buildFeatures.prefab true }
Thêm phần phụ thuộc
GameActivity
vào ứng dụng của bạn:- Thêm thư viện
core
và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-activity
yê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.gradle
mớ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
MainActivity
là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/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>
Á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.txt
add_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.txt
của dự án, hãy nhập thư viện tĩnhgame-activity
và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.txt
của dự án, hãy nhập góigame-activity
và thêm gói đó vào mục tiêu của bạn. Góigame-activity
yê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_glue
củ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.h
thà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
AInputEvent
và thay thế mã đó bằng cách triển khaiInputBuffer
củ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_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; }
Xem lại và cập nhật logic được liên kết với
AInputEvent
của NativeActivity. Như đã thấy trong bước trước, quá trình xử lýInputBuffer
của GameActivity nằm ngoài vòng lặpALooper_pollAll()
.Thay thế mức sử dụng
android_app::activity->clazz
bằ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.