GameActivity का इस्तेमाल शुरू करना Android Game Development Kit का हिस्सा.
इस गाइड में, Android गेम में GameActivity
को सेट अप और इंटिग्रेट करने का तरीका बताया गया है. साथ ही, इसमें इवेंट मैनेज करने का तरीका भी बताया गया है.
GameActivity
की मदद से, C या C++ गेम को Android पर लाया जा सकता है. इससे ज़रूरी एपीआई इस्तेमाल करने की प्रोसेस आसान हो जाती है.
पहले, गेम के लिए NativeActivity
क्लास का इस्तेमाल करने का सुझाव दिया जाता था. GameActivity
को गेम के लिए सुझाए गए क्लास के तौर पर इस्तेमाल किया जाता है. यह एपीआई लेवल 19 के साथ काम करता है.
GameActivity को इंटिग्रेट करने वाले सैंपल के लिए, games-samples repository देखें.
शुरू करने से पहले
बंटन पाने के लिए, GameActivity
रिलीज़ देखें.
बिल्ड सेट अप करना
Android पर, Activity
आपके गेम के लिए एंट्री पॉइंट के तौर पर काम करता है. साथ ही, यह Window
भी उपलब्ध कराता है, ताकि गेम के अंदर ड्रॉ किया जा सके. कई गेम, Activity
को अपनी Java या Kotlin क्लास के साथ बढ़ाते हैं, ताकि NativeActivity
में मौजूद सीमाओं को दूर किया जा सके. साथ ही, JNI
कोड का इस्तेमाल करके, अपने C या C++ गेम कोड को ब्रिज किया जा सके.
GameActivity
में ये सुविधाएं मिलती हैं:
यह
AppCompatActivity
से इनहेरिट करता है. इससे आपको Android Jetpack Architecture Components का इस्तेमाल करने की अनुमति मिलती है.यह
SurfaceView
में रेंडर होता है. इससे आपको किसी भी Android यूज़र इंटरफ़ेस (यूआई) एलिमेंट के साथ इंटरफ़ेस करने की सुविधा मिलती है.यह कुकी, Java गतिविधि के इवेंट मैनेज करती है. इससे किसी भी Android यूज़र इंटरफ़ेस (यूआई) एलिमेंट (जैसे कि
EditText
,WebView
याAd
) को C इंटरफ़ेस के ज़रिए आपके गेम में इंटिग्रेट किया जा सकता है.यह
NativeActivity
औरandroid_native_app_glue
लाइब्रेरी की तरह ही C API उपलब्ध कराता है.
GameActivity
को Android Archive (AAR) के तौर पर डिस्ट्रिब्यूट किया जाता है. इस एएआर में Java क्लास शामिल है. इसका इस्तेमाल AndroidManifest.xml
में किया जाता है. साथ ही, इसमें C और C++ सोर्स कोड भी शामिल है. यह कोड, GameActivity
के Java हिस्से को ऐप्लिकेशन के C/C++ कोड से कनेक्ट करता है. अगर GameActivity
1.2.2 या इसके बाद के वर्शन का इस्तेमाल किया जा रहा है, तो C/C++ स्टैटिक लाइब्रेरी भी उपलब्ध कराई जाती है. हमारा सुझाव है कि जब भी लागू हो, तब सोर्स कोड के बजाय स्टैटिक लाइब्रेरी का इस्तेमाल करें.
इन सोर्स फ़ाइलों या स्टैटिक लाइब्रेरी को अपनी बिल्ड प्रोसेस में शामिल करें. इसके लिए, Prefab
का इस्तेमाल करें. इससे नेटिव लाइब्रेरी और सोर्स कोड, आपके CMake प्रोजेक्ट या NDK बिल्ड के लिए उपलब्ध हो जाते हैं.
अपने गेम की
build.gradle
फ़ाइल मेंGameActivity
लाइब्रेरी डिपेंडेंसी जोड़ने के लिए, Jetpack Android Games पेज पर दिए गए निर्देशों का पालन करें.Android प्लगिन वर्शन (एजीपी) 4.1 या इसके बाद के वर्शन के साथ, यहां दिया गया तरीका अपनाकर प्रीफ़ैब चालू करें:
- अपने मॉड्यूल की
build.gradle
फ़ाइल केandroid
ब्लॉक में यह कोड जोड़ें:
buildFeatures { prefab true }
- प्रीफ़ैब का कोई वर्शन चुनें
और उसे
gradle.properties
फ़ाइल पर सेट करें:
android.prefabVersion=2.0.0
अगर AGP के पुराने वर्शन का इस्तेमाल किया जाता है, तो कॉन्फ़िगरेशन के निर्देशों के लिए, प्रीफ़ैब के दस्तावेज़ पढ़ें.
- अपने मॉड्यूल की
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)
इसके अलावा, अपने प्रोजेक्ट के
CmakeLists.txt
में ये फ़ाइलें भी शामिल करें:GameActivity.cpp
,GameTextInput.cpp
, औरandroid_native_app_glue.c
.
Android आपकी ऐक्टिविटी को कैसे लॉन्च करता है
Android सिस्टम, आपकी ऐक्टिविटी के इंस्टेंस में कोड को एक्ज़ीक्यूट करता है. इसके लिए, वह ऐक्टिविटी की लाइफ़साइकल के खास चरणों से जुड़े कॉलबैक मैथड को शुरू करता है. Android को आपकी गतिविधि लॉन्च करने और गेम शुरू करने के लिए, आपको Android मेनिफ़ेस्ट में सही एट्रिब्यूट के साथ अपनी गतिविधि का एलान करना होगा. ज़्यादा जानकारी के लिए, गतिविधियों के बारे में जानकारी लेख पढ़ें.
Android मेनिफ़ेस्ट
हर ऐप्लिकेशन प्रोजेक्ट में, प्रोजेक्ट सोर्स सेट के रूट में AndroidManifest.xml फ़ाइल होनी चाहिए. मेनिफ़ेस्ट फ़ाइल में, Android बिल्ड टूल, Android ऑपरेटिंग सिस्टम, और Google Play को आपके ऐप्लिकेशन के बारे में ज़रूरी जानकारी मिलती है. इकट्ठा की जाने वाली जानकारी में यह शामिल है:
Google Play पर आपके गेम की खास तौर पर पहचान करने के लिए, पैकेज का नाम और ऐप्लिकेशन आईडी.
ऐप्लिकेशन के कॉम्पोनेंट, जैसे कि ऐक्टिविटी, सेवाएं, ब्रॉडकास्ट रिसीवर, और कॉन्टेंट उपलब्ध कराने वाली कंपनियां.
सिस्टम के सुरक्षित हिस्सों या अन्य ऐप्लिकेशन को ऐक्सेस करने के लिए अनुमतियां.
डिवाइस के साथ काम करने की सुविधा इससे आपके गेम के लिए हार्डवेयर और सॉफ़्टवेयर से जुड़ी ज़रूरी शर्तों के बारे में जानकारी मिलती है.
GameActivity
औरNativeActivity
के लिए नेटिव लाइब्रेरी का नाम(डिफ़ॉल्ट रूप से libmain.so होता है).
अपने गेम में GameActivity लागू करना
अपनी मुख्य गतिविधि वाली Java क्लास बनाएं या उसे पहचानें. यह वही क्लास है जिसे आपकी
AndroidManifest.xml
फ़ाइल में मौजूदactivity
एलिमेंट में तय किया गया है. इस क्लास को बदलकर,com.google.androidgamesdk
पैकेज सेGameActivity
को एक्सटेंड करें:import com.google.androidgamesdk.GameActivity; public class YourGameActivity extends GameActivity { ... }
पक्का करें कि आपकी नेटिव लाइब्रेरी, स्टैटिक ब्लॉक का इस्तेमाल करके शुरू में लोड हो गई हो:
public class EndlessTunnelActivity extends GameActivity { static { // Load the native library. // The name "android-game" depends on your CMake configuration, must be // consistent here and inside AndroidManifect.xml System.loadLibrary("android-game"); } ... }
अगर आपकी लाइब्रेरी का नाम डिफ़ॉल्ट नाम (
libmain.so
) नहीं है, तो अपनी नेटिव लाइब्रेरी कोAndroidManifest.xml
में जोड़ें:<meta-data android:name="android.app.lib_name" android:value="android-game" />
android_main लागू करना
android_native_app_glue
लाइब्रेरी, सोर्स कोड लाइब्रेरी है. आपका गेम इसका इस्तेमाल,GameActivity
के लाइफ़साइकल इवेंट को मैनेज करने के लिए करता है. ऐसा अलग थ्रेड में किया जाता है, ताकि आपकी मुख्य थ्रेड ब्लॉक न हो. लाइब्रेरी का इस्तेमाल करते समय, आपको लाइफ़साइकल इवेंट को मैनेज करने के लिए कॉलबैक रजिस्टर करना होता है. जैसे, टच इनपुट इवेंट.GameActivity
संग्रह में,android_native_app_glue
लाइब्रेरी का अपना वर्शन शामिल होता है. इसलिए, NDK रिलीज़ में शामिल वर्शन का इस्तेमाल नहीं किया जा सकता. अगर आपके गेम, NDK में शामिलandroid_native_app_glue
लाइब्रेरी का इस्तेमाल कर रहे हैं, तोGameActivity
वर्शन पर स्विच करें.android_native_app_glue
लाइब्रेरी के सोर्स कोड को अपने प्रोजेक्ट में जोड़ने के बाद, यहGameActivity
के साथ इंटरफ़ेस करता है.android_main
नाम का एक फ़ंक्शन लागू करें. इसे लाइब्रेरी कॉल करती है और इसका इस्तेमाल आपके गेम के एंट्री पॉइंट के तौर पर किया जाता है. इसेandroid_app
नाम का स्ट्रक्चर पास किया जाता है. यह आपके गेम और इंजन के हिसाब से अलग-अलग हो सकता है. यहां एक उदाहरण दिया गया है:#include <game-activity/native_app_glue/android_native_app_glue.h> extern "C" { void android_main(struct android_app* state); }; void android_main(struct android_app* app) { NativeEngine *engine = new NativeEngine(app); engine->GameLoop(); delete engine; }
android_app
को अपने गेम के मुख्य लूप में प्रोसेस करें. जैसे, NativeAppGlueAppCmd में तय किए गए ऐप्लिकेशन साइकल इवेंट को पोल करना और हैंडल करना. उदाहरण के लिए, यहां दिए गए स्निपेट में, फ़ंक्शन_hand_cmd_proxy
कोNativeAppGlueAppCmd
हैंडलर के तौर पर रजिस्टर किया गया है. इसके बाद, यह ऐप्लिकेशन के साइकल इवेंट को पोल करता है और उन्हें प्रोसेस करने के लिए, रजिस्टर किए गए हैंडलर(android_app::onAppCmd
में) को भेजता है:void NativeEngine::GameLoop() { mApp->userData = this; mApp->onAppCmd = _handle_cmd_proxy; // register your command handler. mApp->textInputState = 0; while (1) { int events; struct android_poll_source* source; // If not animating, block until we get an event; // If animating, don't block. while ((ALooper_pollOnce(IsAnimating() ? 0 : -1, NULL, &events, (void **) &source)) >= 0) { if (source != NULL) { // process events, native_app_glue internally sends the outstanding // application lifecycle events to mApp->onAppCmd. source->process(source->app, source); } if (mApp->destroyRequested) { return; } } if (IsAnimating()) { DoFrame(); } } }
इस बारे में और पढ़ने के लिए, एंडलेस टनल NDK के उदाहरण को लागू करने के बारे में पढ़ें. मुख्य अंतर यह होगा कि इवेंट को कैसे हैंडल किया जाए. इसके बारे में अगले सेक्शन में बताया गया है.
इवेंट हैंडल करना
अपने ऐप्लिकेशन तक इनपुट इवेंट पहुंचने की सुविधा चालू करने के लिए, android_app_set_motion_event_filter
और android_app_set_key_event_filter
का इस्तेमाल करके, इवेंट फ़िल्टर बनाएं और उन्हें रजिस्टर करें.
डिफ़ॉल्ट रूप से, native_app_glue
लाइब्रेरी सिर्फ़ SOURCE_TOUCHSCREEN इनपुट से मोशन इवेंट की अनुमति देती है. ज़्यादा जानकारी के लिए, रेफ़रंस दस्तावेज़ और android_native_app_glue
लागू करने का कोड देखें.
इनपुट इवेंट को हैंडल करने के लिए, अपने गेम लूप में android_input_buffer
का रेफ़रंस पाएं. इसके लिए, android_app_swap_input_buffers()
का इस्तेमाल करें. इनमें मोशन इवेंट और मुख्य इवेंट शामिल होते हैं. ये इवेंट, आखिरी बार पोल किए जाने के बाद हुए हैं. motionEventsCount
और keyEventsCount
में, शामिल इवेंट की संख्या सेव की जाती है.
अपने गेम लूप में हर इवेंट को दोहराएं और उसे हैंडल करें. इस उदाहरण में, यहां दिया गया कोड
motionEvents
को दोहराता है और उन्हेंhandle_event
के ज़रिए मैनेज करता है:android_input_buffer* inputBuffer = android_app_swap_input_buffers(app); if (inputBuffer && inputBuffer->motionEventsCount) { for (uint64_t i = 0; i < inputBuffer->motionEventsCount; ++i) { GameActivityMotionEvent* motionEvent = &inputBuffer->motionEvents[i]; if (motionEvent->pointerCount > 0) { const int action = motionEvent->action; const int actionMasked = action & AMOTION_EVENT_ACTION_MASK; // Initialize pointerIndex to the max size, we only cook an // event at the end of the function if pointerIndex is set to a valid index range uint32_t pointerIndex = GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT; struct CookedEvent ev; memset(&ev, 0, sizeof(ev)); ev.motionIsOnScreen = motionEvent->source == AINPUT_SOURCE_TOUCHSCREEN; if (ev.motionIsOnScreen) { // use screen size as the motion range ev.motionMinX = 0.0f; ev.motionMaxX = SceneManager::GetInstance()->GetScreenWidth(); ev.motionMinY = 0.0f; ev.motionMaxY = SceneManager::GetInstance()->GetScreenHeight(); } switch (actionMasked) { case AMOTION_EVENT_ACTION_DOWN: pointerIndex = 0; ev.type = COOKED_EVENT_TYPE_POINTER_DOWN; break; case AMOTION_EVENT_ACTION_POINTER_DOWN: pointerIndex = ((action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); ev.type = COOKED_EVENT_TYPE_POINTER_DOWN; break; case AMOTION_EVENT_ACTION_UP: pointerIndex = 0; ev.type = COOKED_EVENT_TYPE_POINTER_UP; break; case AMOTION_EVENT_ACTION_POINTER_UP: pointerIndex = ((action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); ev.type = COOKED_EVENT_TYPE_POINTER_UP; break; case AMOTION_EVENT_ACTION_MOVE: { // Move includes all active pointers, so loop and process them here, // we do not set pointerIndex since we are cooking the events in // this loop rather than at the bottom of the function ev.type = COOKED_EVENT_TYPE_POINTER_MOVE; for (uint32_t i = 0; i < motionEvent->pointerCount; ++i) { _cookEventForPointerIndex(motionEvent, callback, ev, i); } break; } default: break; } // Only cook an event if we set the pointerIndex to a valid range, note that // move events cook above in the switch statement. if (pointerIndex != GAMEACTIVITY_MAX_NUM_POINTERS_IN_MOTION_EVENT) { _cookEventForPointerIndex(motionEvent, callback, ev, pointerIndex); } } } android_app_clear_motion_events(inputBuffer); }
_cookEventForPointerIndex()
और इससे जुड़े अन्य फ़ंक्शन को लागू करने के लिए, GitHub का सैंपल देखें.जब आपका काम पूरा हो जाए, तो उन इवेंट की कतार को मिटाना न भूलें जिन्हें आपने अभी-अभी हैंडल किया है:
android_app_clear_motion_events(mApp);
अन्य संसाधन
GameActivity
के बारे में ज़्यादा जानने के लिए, यहां जाएं:
- GameActivity और AGDK के रिलीज़ नोट.
- GameActivity में GameTextInput का इस्तेमाल करें.
- NativeActivity माइग्रेशन गाइड.
- GameActivity के रेफ़रंस दस्तावेज़.
- GameActivity लागू करना.
GameActivity में गड़बड़ियों की शिकायत करने या नई सुविधाओं का अनुरोध करने के लिए, GameActivity से जुड़ी समस्या को ट्रैक करने वाले टूल का इस्तेमाल करें.