Android গেম ডেভেলপমেন্ট কিটের GameActivity অংশ দিয়ে শুরু করুন।
এই নির্দেশিকাটি বর্ণনা করে যে কীভাবে GameActivity সেট আপ এবং সংহত করবেন এবং আপনার Android গেমে ইভেন্টগুলি পরিচালনা করবেন।
GameActivity আপনাকে ক্রিটিক্যাল এপিআই ব্যবহার করার প্রক্রিয়াকে সহজ করে আপনার C বা C++ গেমটিকে Android-এ আনতে সাহায্য করে। পূর্বে NativeActivity গেমের জন্য প্রস্তাবিত ক্লাস ছিল। GameActivity এটিকে গেমের জন্য প্রস্তাবিত শ্রেণী হিসাবে প্রতিস্থাপন করে এবং এটি API স্তর 19 এর সাথে পিছনের দিকে সামঞ্জস্যপূর্ণ।
গেমঅ্যাক্টিভিটি সংহত করে এমন একটি নমুনার জন্য, গেমস-নমুনা সংগ্রহস্থল দেখুন।
আপনি শুরু করার আগে
একটি বিতরণ পেতে GameActivity রিলিজ দেখুন।
আপনার বিল্ড সেট আপ করুন
অ্যান্ড্রয়েডে, একটি Activity আপনার গেমের এন্ট্রি পয়েন্ট হিসাবে কাজ করে এবং এর মধ্যে আঁকতে Window প্রদান করে। অনেক গেম তাদের C বা C++ গেম কোডের সাথে ব্রিজ করতে JNI কোড ব্যবহার করার সময় NativeActivity সীমাবদ্ধতাগুলিকে হারাতে তাদের নিজস্ব জাভা বা কোটলিন ক্লাসের সাথে এই Activity প্রসারিত করে।
GameActivity নিম্নলিখিত ক্ষমতা প্রদান করে:
AppCompatActivityথেকে উত্তরাধিকারসূত্রে পাওয়া যায়, যা আপনাকে অ্যান্ড্রয়েড জেটপ্যাক আর্কিটেকচার উপাদান ব্যবহার করতে দেয়।একটি
SurfaceViewরেন্ডার করে যা আপনাকে অন্য যেকোনো Android UI উপাদানের সাথে ইন্টারফেস করতে দেয়।জাভা কার্যকলাপ ইভেন্ট পরিচালনা করে। এটি যেকোন Android UI উপাদানকে (যেমন একটি
EditText, একটিWebViewবা একটিAd) একটি C ইন্টারফেসের মাধ্যমে আপনার গেমের সাথে একীভূত করার অনুমতি দেয়৷NativeActivity, এবংandroid_native_app_glueলাইব্রেরির মতো একটি C API অফার করে।
GameActivity একটি অ্যান্ড্রয়েড আর্কাইভ (AAR) হিসাবে বিতরণ করা হয়। এই AAR-এ জাভা ক্লাস রয়েছে যা আপনি আপনার AndroidManifest.xml এ ব্যবহার করেন, সেইসাথে C এবং C++ সোর্স কোড যা GameActivity জাভা সাইডকে অ্যাপের C/C++ বাস্তবায়নের সাথে সংযুক্ত করে। আপনি যদি GameActivity 1.2.2 বা তার পরে ব্যবহার করেন, C/C++ স্ট্যাটিক লাইব্রেরিও প্রদান করা হয়। যখনই প্রযোজ্য, আমরা সুপারিশ করি যে আপনি সোর্স কোডের পরিবর্তে স্ট্যাটিক লাইব্রেরি ব্যবহার করুন৷
Prefab মাধ্যমে আপনার বিল্ড প্রক্রিয়ার অংশ হিসেবে এই সোর্স ফাইলগুলি বা স্ট্যাটিক লাইব্রেরি অন্তর্ভুক্ত করুন, যা আপনার CMake প্রোজেক্ট বা NDK বিল্ডে নেটিভ লাইব্রেরি এবং সোর্স কোড প্রকাশ করে।
আপনার গেমের
build.gradleফাইলেGameActivityলাইব্রেরি নির্ভরতা যোগ করতে Jetpack 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 ম্যানিফেস্টে উপযুক্ত গুণাবলী সহ আপনার কার্যকলাপ ঘোষণা করতে হবে। আরও তথ্যের জন্য, কার্যক্রমের ভূমিকা দেখুন।
অ্যান্ড্রয়েড ম্যানিফেস্ট
প্রতিটি অ্যাপ প্রোজেক্টের প্রোজেক্ট সোর্স সেটের রুটে একটি AndroidManifest.xml ফাইল থাকতে হবে। ম্যানিফেস্ট ফাইলটি Android বিল্ড টুল, অ্যান্ড্রয়েড অপারেটিং সিস্টেম এবং Google Play-তে আপনার অ্যাপ সম্পর্কে প্রয়োজনীয় তথ্য বর্ণনা করে। এর মধ্যে রয়েছে:
Google Play-তে আপনার গেমটিকে অনন্যভাবে শনাক্ত করতে প্যাকেজের নাম এবং অ্যাপ আইডি ।
অ্যাপ্লিকেশান উপাদান যেমন কার্যকলাপ, পরিষেবা, সম্প্রচার রিসিভার, এবং বিষয়বস্তু প্রদানকারী.
সিস্টেমের সুরক্ষিত অংশ বা অন্যান্য অ্যাপ অ্যাক্সেস করার অনুমতি ।
আপনার গেমের জন্য হার্ডওয়্যার এবং সফ্টওয়্যার প্রয়োজনীয়তা নির্দিষ্ট করতে ডিভাইসের সামঞ্জস্যতা ।
GameActivityএবংNativeActivityজন্য নেটিভ লাইব্রেরির নাম ( ডিফল্ট হল libmain.so )।
আপনার গেমে গেম অ্যাক্টিভিটি প্রয়োগ করুন
আপনার প্রধান অ্যাক্টিভিটি জাভা ক্লাস তৈরি করুন বা শনাক্ত করুন (আপনার
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"); } ... }AndroidManifest.xmlএ আপনার নেটিভ লাইব্রেরি যোগ করুন যদি আপনার লাইব্রেরির নাম ডিফল্ট নাম না হয় (libmain.so):<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 রিলিজে অন্তর্ভুক্ত সংস্করণটি ব্যবহার করতে পারবেন না। যদি আপনার গেমগুলি এনডিকে-তে অন্তর্ভুক্ত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 এ সংজ্ঞায়িত অ্যাপ সাইকেল ইভেন্ট পোলিং এবং পরিচালনা করুন। উদাহরণস্বরূপ, নিম্নলিখিত স্নিপেটটিNativeAppGlueAppCmdহ্যান্ডলার হিসাবে_hand_cmd_proxyফাংশন নিবন্ধন করে, তারপরে অ্যাপ চক্রের ইভেন্টগুলি পোল করে এবং প্রক্রিয়াকরণের জন্য নিবন্ধিত হ্যান্ডলারের কাছে (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 implmenetation কোড পরীক্ষা করে দেখুন।
ইনপুট ইভেন্টগুলি পরিচালনা করতে, আপনার গেম লুপে android_app_swap_input_buffers() সহ android_input_buffer এর একটি রেফারেন্স পান৷ এর মধ্যে মোশন ইভেন্ট এবং মূল ইভেন্ট রয়েছে যা শেষবার পোল হওয়ার পর থেকে ঘটেছে। উপস্থিত ইভেন্টের সংখ্যা যথাক্রমে 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 সম্পর্কে আরও জানতে, নিম্নলিখিতগুলি দেখুন:
- গেমঅ্যাক্টিভিটি এবং AGDK রিলিজ নোট ।
- GameActivity-এ GameTextInput ব্যবহার করুন ।
- নেটিভ অ্যাক্টিভিটি মাইগ্রেশন গাইড ।
- গেম অ্যাক্টিভিটি রেফারেন্স ডকুমেন্টেশন ।
- গেমঅ্যাক্টিভিটি বাস্তবায়ন ।
বাগ রিপোর্ট করতে বা GameActivity-তে নতুন বৈশিষ্ট্যের অনুরোধ করতে, GameActivity সমস্যা ট্র্যাকার ব্যবহার করুন।