این سند نحوه راهاندازی و نمایش «کیت توسعه نرمافزار ورودی» در بازیهایی را که از «بازیهای Google Play در رایانه» پشتیبانی میکنند شرح میدهد. این وظایف شامل افزودن «کیت توسعه نرمافزار» به بازی و تولید نقشه ورودی است که حاوی تخصیصهای کنشهای بازی به ورودی کاربر است.
قبل از شروع به کار
قبلاز افزودن «کیت توسعه نرمافزار ورودی» به بازیتان، باید از ورودی صفحهکلید و موشواره بااستفاده از سیستم ورودی موتور بازیتان پشتیبانی کنید.
«کیت توسعه نرمافزار ورودی» اطلاعاتی درباره کنترلهایی که بازیتان استفاده میکند به «بازیهای Google Play در رایانه» ارائه میدهد تا این کنترلها به کاربر نمایش داده شوند. همچنین میتواند بهصورت اختیاری به کاربران اجازه دهد صفحهکلید را دوباره تخصیص دهند.
هر کنترل یک InputAction است (برای نمونه، «J» برای «پرش») و InputActions را در InputGroups سازماندهی میکنید. InputGroup ممکن است نشاندهنده حالت متفاوتی در بازی شما باشد، مثل «رانندگی» یا «پیادهروی» یا «منو اصلی». همچنین میتوانید از InputContexts برای نشان دادن اینکه کدام گروهها در نقاط مختلف بازی فعال هستند استفاده کنید.
میتوانید «تغییر تخصیص صفحهکلید» را فعال کنید تا بهطور خودکار برایتان انجام شود، اما اگر ترجیح میدهید رابط تغییر تخصیص کنترل خودتان را ارائه دهید، میتوانید «تغییر تخصیص کیت توسعه نرمافزار ورودی» را غیرفعال کنید.
نمودار توالی زیر نحوه عملکرد API «کیت توسعه نرمافزار ورودی» را شرح میدهد:

وقتی بازیتان «کیت توسعه نرمافزار ورودی» را پیادهسازی میکند، کنترلهایتان در رونهاد «بازیهای Google Play در رایانه» نمایش داده میشود.
روپوش «بازیهای Google Play در رایانه»
روپوش «بازیهای Google Play در رایانه» («روپوش») کنترلهای تعریفشده توسط بازی شما را نمایش میدهد. کاربران با فشار دادن کلید تبدیل + کلید جهش در هر زمانی به رونهاد دسترسی پیدا میکنند.

روالهای مطلوب برای طراحی بستهای کلید
هنگام طراحی کلیدهای میانبر، روالهای مطلوب زیر را درنظر بگیرید:
InputActionsخود را درInputGroupsمرتبط منطقی گروهبندی کنید تا پیمایش و قابلیت شناسایی کنترلها درطول بازی بهبود یابد.- هر
InputGroupرا حداکثر به یکInputContextاختصاص دهید. جزئیات دقیقInputMapمنجر به تجربه بهتری برای پیمایش کنترلها در رونهاد میشود. - برای هر نوع صحنه متفاوت در بازیتان،
InputContextبسازید. معمولاً میتوانید از یکInputContextبرای همه صحنههای «منو مانند» استفاده کنید. برای هر بازی کوچکی در بازیتان یا برای کنترلهای جایگزین برای یک صحنه، ازInputContextsمختلف استفاده کنید. - اگر دو کنش برای استفاده از یک کلید در یک
InputContextطراحی شدهاند، از رشته برچسبی مثل «تعامل / شلیک» استفاده کنید. - اگر دو کلید برای اتصال به یک
InputActionطراحی شدهاند، از ۲InputActionsمتفاوت استفاده کنید که همان کنش را در بازی شما انجام میدهند. میتوانید از رشته برچسب یکسانی برای هر دوInputActionsاستفاده کنید، اما شناسه آن باید متفاوت باشد. - اگر کلید تغییردهنده به مجموعهای از کلیدها اعمال میشود، بهجای چند
InputActionsکه کلید تغییردهنده را ترکیب میکنند، یکInputActionبا کلید تغییردهنده داشته باشید (مثال: بهجای Shift + W، Shift + A، Shift + S، Shift + D، از Shift و W، A، S، D استفاده کنید). - وقتی کاربر در فیلدهای نوشتاری مینویسد، تخصیص مجدد ورودی بهطور خودکار غیرفعال میشود. برای پیادهسازی فیلدهای نوشتاری Android، روالهای مطلوب را دنبال کنید تا مطمئن شوید
که Android میتواند فیلدهای نوشتاری را در بازیتان شناسایی کند و از تداخل کلیدهای بازنگاریشده
با آنها جلوگیری کند. اگر بازیتان باید از فیلدهای نوشتاری غیرمعمول استفاده کند، میتوانید از
setInputContext()باInputContextحاوی فهرست خالیInputGroupsبرای غیرفعال کردن تخصیص مجدد بهصورت دستی استفاده کنید. - اگر بازیتان از تخصیص مجدد پشتیبانی میکند، درنظر داشته باشید که تخصیصهای کلید خود را بهروز کنید. این عملیاتی حساس است که میتواند با نسخههای ذخیرهشده کاربر تداخل داشته باشد. درصورت امکان، از تغییر شناسههای کنترلهای موجود خودداری کنید.
ویژگی بازنگاری
«بازیهای Google Play در رایانه» از تخصیص مجدد کنترل صفحهکلید براساس پیوند کلیدهایی که بازی شما بااستفاده از «کیت توسعه نرمافزار ورودی» ارائه میدهد پشتیبانی میکند. این اختیاری است و
میتواند کاملاً غیرفعال شود. برای مثال، ممکن است بخواهید رابط بازنگاشت صفحهکلید خودتان را ارائه دهید. برای غیرفعال کردن تخصیص مجدد برای بازیتان، کافی است
گزینه تخصیص مجدد را برای InputMap غیرفعال کنید (برای
اطلاعات بیشتر، ساختن InputMap را ببینید).
برای دسترسی به این ویژگی، کاربران باید رونهاد را باز کنند و سپس روی کنشی که میخواهند مجدداً تخصیص دهند کلیک کنند. پساز هر رویداد تخصیص مجدد، «بازیهای Google Play در رایانه» هر کنترل تخصیصدادهشده مجدد توسط کاربر را به کنترلهای پیشفرضی که بازی شما انتظار دریافت آنها را دارد تخصیص میدهد، بنابراین بازی شما نیازی به آگاهی از تخصیص مجدد بازیکن ندارد. میتوانید بهصورت اختیاری داراییهای استفادهشده برای نمایش کنترلهای صفحهکلید در بازیتان را با افزودن یک بازخوان برای تخصیص مجدد رویدادها بهروز کنید.

«بازیهای Google Play در رایانه» کنترلهای دوباره تخصیصدادهشده را بهصورت محلی برای هر کاربر ذخیره میکند و ماندگاری کنترل را در جلسات بازی امکانپذیر میکند. این اطلاعات فقط برای پلاتفرم رایانه در دیسک ذخیره میشود و بر تجربه تلفن همراه تأثیری ندارد. وقتی کاربر «بازیهای Google Play در رایانه» را حذف نصب یا بازنصب میکند، دادههای کنترل حذف میشود. این دادهها در چند دستگاه رایانه شخصی ماندگار نیست.
برای پشتیبانی از ویژگی تخصیص مجدد در بازیتان، از محدودیتهای زیر اجتناب کنید:
محدودیتهای تخصیص مجدد
اگر کلیدهای تخصیصدادهشده حاوی هریک از موارد زیر باشد، ویژگیهای تخصیص مجدد کلیدها میتواند در بازی غیرفعال شود:
-
InputActionsچندکلیدی که از کلید اصلاحگر + کلید غیر اصلاحگر تشکیل نشدهاند. برای مثال، تبدیل + A معتبر است اما A + B، کنترل + دگرساز، یا تبدیل + A + جهش معتبر نیست. -
InputMapحاویInputActions،InputGroups، یاInputContextsبا شناسههای یکتای تکراری است.
محدودیتهای تخصیص مجدد
هنگام طراحی کلیدهای اختصاصی برای تخصیص مجدد، محدودیتهای زیر را درنظر بگیرید:
- تغییر تخصیص به ترکیبهای کلید پشتیبانی نمیشود. برای مثال، کاربران نمیتوانند تبدیل Shift + A به Ctrl + B یا A به Shift + A را انجام دهند.
- تغییر تخصیص برای
InputActionsبا دکمههای موشواره پشتیبانی نمیشود. برای مثال، تبدیل + کلیک راست را نمیتوان دوباره تخصیص داد.
آزمایش کردن تخصیص مجدد کلید در «شبیهساز بازیهای Google Play در رایانه»
هرزمان بخواهید میتوانید ویژگی تخصیص مجدد را در «شبیهساز بازیهای Google Play در رایانه» با اجرای دستور adb زیر فعال کنید:
adb shell dumpsys input_mapping_service --set RemappingFlagValue true
همپوشانی تغییر میکند، همانطور که در تصویر زیر نشان داده شده است:

افزودن کیت توسعه نرمافزار
«کیت توسعه نرمافزار ورودی» را براساس پلاتفرم توسعه خود نصب کنید.
Java و Kotlin
با افزودن وابستگی به فایل build.gradle سطح واحد، Input SDK را برای Java یا Kotlin دریافت کنید:
dependencies {
implementation 'com.google.android.libraries.play.games:inputmapping:1.1.1-beta'
...
}
Unity
«کیت توسعه نرمافزار ورودی» یک بسته استاندارد Unity با چندین وابستگی است.
نصب بسته با همه وابستگیها الزامی است. چندین روش برای نصب بستهها وجود دارد.
نصب .unitypackage
فایل unitypackage «کیت توسعه نرمافزار ورودی»
را با همه وابستگیهایش بارگیری کنید. میتوانید .unitypackage را با انتخاب
داراییها > وارد کردن بسته > بسته سفارشی و پیدا کردن فایل بارگیریشده نصب کنید.
نصب بااستفاده از UPM
یا میتوانید بسته را بااستفاده از
مدیر بسته Unity با
بارگیری .tgz و نصب وابستگیهای آن نصب کنید:
- com.google.external-dependency-manager-1.2.172
- com.google.librarywrapper.java-0.2.0
- com.google.librarywrapper.openjdk8-0.2.0
- com.google.android.libraries.play.games.inputmapping-1.1.1-beta (یا انتخاب tgz از این بایگانی)
نصب بااستفاده از OpenUPM
میتوانید بسته را بااستفاده از OpenUPM نصب کنید.
$ openupm add com.google.android.libraries.play.games.inputmapping
بازیهای نمونه
برای مثالهایی از نحوه ادغام با Input SDK، AGDK Tunnel برای بازیهای Kotlin یا Java و Trivial Kart برای بازیهای Unity را ببینید.
تولید بستهای کلید
با ساختن InputMap و برگرداندن آن با InputMappingProvider، پیوندهای کلید خود را ثبت کنید. مثال زیر یک
InputMappingProvider را نشان میدهد:
کاتلین
class InputSDKProvider : InputMappingProvider { override fun onProvideInputMap(): InputMap { TODO("Not yet implemented") } }
جاوا
public class InputSDKProvider implements InputMappingProvider { private static final String INPUTMAP_VERSION = "1.0.0"; @Override @NonNull public InputMap onProvideInputMap() { // TODO: return an InputMap } }
C#
#if PLAY_GAMES_PC using Java.Lang; using Java.Util; using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel; public class InputSDKProvider : InputMappingProviderCallbackHelper { public static readonly string INPUT_MAP_VERSION = "1.0.0"; public override InputMap OnProvideInputMap() { // TODO: return an InputMap } } #endif
کنشهای ورودی را تعریف کنید
از کلاس InputAction برای تخصیص کلید یا ترکیب کلید به کنش بازی استفاده میشود. InputActions باید در همه InputActions شناسههای یکتا داشته باشد.
اگر از تخصیص مجدد پشتیبانی میکنید، میتوانید تعریف کنید که InputActions میتواند
مجدداً تخصیص داده شود. اگر بازیتان از تخصیص مجدد پشتیبانی نمیکند، باید گزینه تخصیص مجدد را برای همه InputActions غیرفعال کنید، اما «کیت توسعه نرمافزار ورودی» بهاندازه کافی هوشمند است که اگر در InputMap از آن پشتیبانی نکنید، تخصیص مجدد را غیرفعال کند.
این مثال کلید
کاتلین
companion object { private val driveInputAction = InputAction.create( "Drive", InputActionsIds.DRIVE.ordinal.toLong(), InputControls.create(listOf(KeyEvent.KEYCODE_SPACE), emptyList()), InputEnums.REMAP_OPTION_ENABLED) }
جاوا
private static final InputAction driveInputAction = InputAction.create( "Drive", InputEventIds.DRIVE.ordinal(), InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_SPACE), Collections.emptyList()), InputEnums.REMAP_OPTION_ENABLED );
C#
private static readonly InputAction driveInputAction = InputAction.Create( "Drive", (long)InputEventIds.DRIVE, InputControls.Create( new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(), new ArrayList<Integer>()), InputEnums.REMAP_OPTION_ENABLED );

کنشها میتوانند نشاندهنده ورودیهای موشواره نیز باشند. این مثال کلیک چپ را روی کنش انتقال تنظیم میکند:
کاتلین
companion object { private val mouseInputAction = InputAction.create( "Move", InputActionsIds.MOUSE_MOVEMENT.ordinal.toLong(), InputControls.create(emptyList(), listOf(InputControls.MOUSE_LEFT_CLICK)), InputEnums.REMAP_OPTION_DISABLED) }
جاوا
private static final InputAction mouseInputAction = InputAction.create( "Move", InputActionsIds.MOUSE_MOVEMENT.ordinal(), InputControls.create( Collections.emptyList(), Collections.singletonList(InputControls.MOUSE_LEFT_CLICK) ), InputEnums.REMAP_OPTION_DISABLED );
C#
private static readonly InputAction mouseInputAction = InputAction.Create( "Move", (long)InputEventIds.MOUSE_MOVEMENT, InputControls.Create( new ArrayList<Integer>(), new[] { new Integer((int)PlayMouseAction.MouseLeftClick) }.ToJavaList() ), InputEnums.REMAP_OPTION_DISABLED );

ترکیبهای کلید با ارسال چندین کد کلید به InputAction شما مشخص میشوند. در این مثال،
کاتلین
companion object { private val turboInputAction = InputAction.create( "Turbo", InputActionsIds.TURBO.ordinal.toLong(), InputControls.create( listOf(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SPACE), emptyList()), InputEnums.REMAP_OPTION_ENABLED) }
جاوا
private static final InputAction turboInputAction = InputAction.create( "Turbo", InputActionsIds.TURBO.ordinal(), InputControls.create( Arrays.asList(KeyEvent.KEYCODE_SHIFT_LEFT, KeyEvent.KEYCODE_SPACE), Collections.emptyList() ), InputEnums.REMAP_OPTION_ENABLED );
C#
private static readonly InputAction turboInputAction = InputAction.Create( "Turbo", (long)InputEventIds.TURBO, InputControls.Create( new[] { new Integer(AndroidKeyCode.KEYCODE_SHIFT_LEFT), new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(), new ArrayList<Integer>()), InputEnums.REMAP_OPTION_ENABLED );

«کیت توسعه نرمافزار ورودی» به شما امکان میدهد دکمههای موشواره و صفحهکلید را برای یک کنش واحد با هم ترکیب کنید. این مثال نشان میدهد که
کاتلین
companion object { private val addWaypointInputAction = InputAction.create( "Add waypoint", InputActionsIds.ADD_WAYPOINT.ordinal.toLong(), InputControls.create( listOf(KeyEvent.KeyEvent.KEYCODE_TAB), listOf(InputControls.MOUSE_RIGHT_CLICK)), InputEnums.REMAP_OPTION_DISABLED) }
جاوا
private static final InputAction addWaypointInputAction = InputAction.create( "Add waypoint", InputActionsIds.ADD_WAYPOINT.ordinal(), InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_TAB), Collections.singletonList(InputControls.MOUSE_RIGHT_CLICK) ), InputEnums.REMAP_OPTION_DISABLED );
C#
private static readonly InputAction addWaypointInputAction = InputAction.Create( "Add waypoint", (long)InputEventIds.ADD_WAYPOINT, InputControls.Create( new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE) }.ToJavaList(), new[] { new Integer((int)PlayMouseAction.MouseRightClick) }.ToJavaList() ), InputEnums.REMAP_OPTION_DISABLED );

InputAction فیلدهای زیر را دارد:
-
ActionLabel: رشتهای که در رابط کاربری برای نشان دادن این کنش نمایش داده میشود. بومیسازی بهطور خودکار انجام نمیشود، بنابراین هر بومیسازی را ازقبل انجام دهید. -
InputControls: کنترلهای ورودی را که این کنش استفاده میکند تعریف میکند. این کنترلها به گلیکهای سازگار در رونهاد نگاشت میشوند. -
InputActionId: شیءInputIdentifierکه شناسه شماره و نسخهInputActionرا ذخیره میکند (برای اطلاعات بیشتر، شناسههای کلید پیگیری را ببینید). -
InputRemappingOption: یکی ازInputEnums.REMAP_OPTION_ENABLEDیاInputEnums.REMAP_OPTION_DISABLED. تعریف میکند که آیا کنش برای تغییر تخصیص کلید فعال است یا نه. اگر بازی شما از تخصیص مجدد پشتیبانی نمیکند، میتوانید از این فیلد رد شوید یا آن را غیرفعال کنید. -
RemappedInputControls: شیءInputControlsفقطخواندنی که برای خواندن مجموعه کلیدهای مجدداً تخصیصدادهشده توسط کاربر در رویدادهای تخصیص مجدد استفاده میشود (برای دریافت اعلان درباره رویدادهای تخصیص مجدد استفاده میشود).
InputControls نشاندهنده ورودیهای مرتبط با کنش است و حاوی فیلدهای زیر است::
-
AndroidKeycodes: فهرستی از اعداد صحیح است که نشاندهنده ورودیهای صفحهکلید مرتبط با یک کنش است. اینها در کلاس KeyEvent یا کلاس AndroidKeycode برای Unity تعریف شدهاند. MouseActions: فهرستی ازMouseActionمقدار است که نشاندهنده ورودیهای موشواره مرتبط با این کنش است.
تعریف کردن گروههای ورودی
InputActions بااستفاده از InputGroups با کنشهای منطقاً مرتبط گروهبندی میشوند تا
پیمایش و قابلیت کشف کنترلها در رونهاد بهبود یابد. هر شناسه InputGroup باید در همه InputGroups در بازی شما یکتا باشد.
با سازماندهی کنشهای ورودی در گروهها، پیدا کردن کلیدهای مناسب برای بافت کنونی را برای بازیکن آسانتر میکنید.
اگر از تخصیص مجدد پشتیبانی میکنید، میتوانید تعریف کنید که InputGroups میتواند
مجدداً تخصیص داده شود. اگر بازیتان از تخصیص مجدد پشتیبانی نمیکند، باید گزینه تخصیص مجدد را برای همه InputGroups غیرفعال کنید، اما «کیت توسعه نرمافزار ورودی» بهاندازه کافی هوشمند است که اگر در InputMap از آن پشتیبانی نکنید، تخصیص مجدد را غیرفعال کند.
کاتلین
companion object { private val menuInputGroup = InputGroup.create( "Menu keys", listOf( navigateUpInputAction, navigateLeftInputAction, navigateDownInputAction, navigateRightInputAction, openMenuInputAction, returnMenuInputAction), InputGroupsIds.MENU_ACTION_KEYS.ordinal.toLong(), InputEnums.REMAP_OPTION_ENABLED ) }
جاوا
private static final InputGroup menuInputGroup = InputGroup.create( "Menu keys", Arrays.asList( navigateUpInputAction, navigateLeftInputAction, navigateDownInputAction, navigateRightInputAction, openMenuInputAction, returnMenuInputAction), InputGroupsIds.MENU_ACTION_KEYS.ordinal(), REMAP_OPTION_ENABLED );
C#
private static readonly InputGroup menuInputGroup = InputGroup.Create( "Menu keys", new[] { navigateUpInputAction, navigateLeftInputAction, navigateDownInputAction, navigateRightInputAction, openMenuInputAction, returnMenuInputAction, }.ToJavaList(), (long)InputGroupsIds.MENU_ACTION_KEYS, InputEnums.REMAP_OPTION_ENABLED );
مثال زیر کنترلهای جاده و کنترلهای منو گروههای ورودی را در رونهاد نمایش میدهد:

InputGroup فیلدهای زیر را دارد:
-
GroupLabel: رشتهای که در رونهاد نمایش داده میشود و میتواند برای گروهبندی منطقی مجموعهای از کنشها استفاده شود. این رشته بهطور خودکار بومیسازی نمیشود. -
InputActions: فهرستی ازInputActionشیء که در مرحله قبلی تعریف میکنید. همه این کنشها بهصورت تصویری در زیر عنوان گروه نمایش داده میشوند. -
InputGroupId: شیءInputIdentifierکه شناسه شماره و نسخهInputGroupرا ذخیره میکند. برای اطلاعات بیشتر، شناسههای کلید پیگیری را ببینید. -
InputRemappingOption: یکی ازInputEnums.REMAP_OPTION_ENABLEDیاInputEnums.REMAP_OPTION_DISABLED. اگر غیرفعال شود، همهInputActionاشیاء متعلق به این گروه حتی اگر گزینه تخصیص مجدد آن را فعال مشخص کرده باشند، تخصیص مجددشان غیرفعال خواهد شد. اگر فعال شود، همه کنشهای متعلق به این گروه میتوانند دوباره تخصیص داده شوند، مگر اینکه کنشهای جداگانه مشخص کرده باشند که غیرفعال شوند.
تعریف زمینههای ورودی
InputContexts به بازی شما امکان میدهد از مجموعه متفاوتی از کنترلهای صفحهکلید برای صحنههای مختلف بازی استفاده کند. برای مثال:
- میتوانید مجموعههای ورودی متفاوتی برای پیمایش منوها درمقایسه با حرکت در بازی مشخص کنید.
- بسته به حالت حرکت در بازیتان، مثل رانندگی دربرابر پیادهروی، میتوانید مجموعههای ورودی متفاوتی مشخص کنید.
- میتوانید براساس وضعیت فعلی بازیتان، مجموعههای مختلفی از ورودیها را مشخص کنید، مثلاً پیمایش در دنیای بالا درمقایسه با بازی در یک سطح مجزا.
هنگام استفاده از InputContexts، رونهاد ابتدا گروههای بافت درحال استفاده را نشان میدهد. برای فعال کردن این رفتار، هرگاه بازیتان وارد صحنه دیگری میشود، setInputContext() را فراخوانی کنید تا زمینه را تنظیم کند. تصویر زیر این رفتار را نشان میدهد: در صحنه «رانندگی»، کنشهای کنترلهای جاده در بالای رونهاد نشان داده میشود. هنگام باز کردن منو «فروشگاه»، کنشهای
«کنترلهای منو» در بالای رونهاد نمایش داده میشود.

این بهروزرسانیهای رونهاد با تنظیم InputContext متفاوت در
نقاط مختلف بازی شما بهدست میآیند. برای انجام این کار:
-
InputActionsخود را با کنشهای منطقی مرتبط بااستفاده ازInputGroupsگروهبندی کنید - این
InputGroupsرا بهInputContextبرای بخشهای مختلف بازیتان اختصاص دهید
InputGroups متعلق به همانInputContextنمیتواند
InputActions متضادی داشته باشد که در آن از کلید یکسانی استفاده شده است. بهتر است هر InputGroup را به یک InputContext اختصاص دهید.
کد نمونه زیر منطق InputContext را نشان میدهد:
کاتلین
companion object { val menuSceneInputContext = InputContext.create( "Menu", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.MENU_SCENE.ordinal.toLong()), listOf(basicMenuNavigationInputGroup, menuActionsInputGroup)) val gameSceneInputContext = InputContext.create( "Game", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.GAME_SCENE.ordinal.toLong()), listOf( movementInputGroup, mouseActionsInputGroup, emojisInputGroup, gameActionsInputGroup)) }
جاوا
public static final InputContext menuSceneInputContext = InputContext.create( "Menu", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.MENU_SCENE.ordinal()), Arrays.asList( basicMenuNavigationInputGroup, menuActionsInputGroup ) ); public static final InputContext gameSceneInputContext = InputContext.create( "Game", InputIdentifier.create( INPUTMAP_VERSION, InputContextIds.GAME_SCENE.ordinal()), Arrays.asList( movementInputGroup, mouseActionsInputGroup, emojisInputGroup, gameActionsInputGroup ) );
C#
public static readonly InputContext menuSceneInputContext = InputContext.Create( "Menu", InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputContextsIds.MENU_SCENE), new[] { basicMenuNavigationInputGroup, menuActionsInputGroup }.ToJavaList() ); public static readonly InputContext gameSceneInputContext = InputContext.Create( "Game", InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputContextsIds.GAME_SCENE), new[] { movementInputGroup, mouseActionsInputGroup, emojisInputGroup, gameActionsInputGroup }.ToJavaList() );
InputContext فیلدهای زیر را دارد:
-
LocalizedContextLabel: رشتهای که گروههای متعلق به بافت را توصیف میکند. -
InputContextId: شیءInputIdentifierکه شناسه شماره و نسخهInputContextرا ذخیره میکند (برای اطلاعات بیشتر، شناسههای کلید پیگیری را ببینید). -
ActiveGroups: فهرستی ازInputGroupsکه باید وقتی این زمینه فعال است در بالای رونهاد استفاده و نمایش داده شود.
ساختن نقشه ورودی
InputMap مجموعهای از همه اشیای InputGroup دردسترس در یک بازی است، و بنابراین همه اشیای InputAction که بازیکن میتواند انتظار داشته باشد انجام دهد.
هنگام گزارش کردن تخصیصهای کلید، InputMap با همه
InputGroups استفادهشده در بازیتان میسازید.
اگر بازیتان از تخصیص مجدد پشتیبانی نمیکند، گزینه تخصیص مجدد را روی غیرفعال تنظیم کنید و کلیدهای رزروشده را خالی بگذارید.
مثال زیر InputMap را میسازد که برای گزارش مجموعه
InputGroups استفاده میشود.
کاتلین
companion object { val gameInputMap = InputMap.create( listOf( basicMenuNavigationInputGroup, menuActionKeysInputGroup, movementInputGroup, mouseMovementInputGroup, pauseMenuInputGroup), MouseSettings.create(true, false), InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID.toLong()), InputEnums.REMAP_OPTION_ENABLED, // Use ESCAPE as reserved remapping key listof(InputControls.create(listOf(KeyEvent.KEYCODE_ESCAPE), emptyList())) ) }
جاوا
public static final InputMap gameInputMap = InputMap.create( Arrays.asList( basicMenuNavigationInputGroup, menuActionKeysInputGroup, movementInputGroup, mouseMovementInputGroup, pauseMenuInputGroup), MouseSettings.create(true, false), InputIdentifier.create(INPUTMAP_VERSION, INPUT_MAP_ID), REMAP_OPTION_ENABLED, // Use ESCAPE as reserved remapping key Arrays.asList( InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_ESCAPE), Collections.emptyList() ) ) );
C#
public static readonly InputMap gameInputMap = InputMap.Create( new[] { basicMenuNavigationInputGroup, menuActionKeysInputGroup, movementInputGroup, mouseMovementInputGroup, pauseMenuInputGroup, }.ToJavaList(), MouseSettings.Create(true, false), InputIdentifier.Create(INPUT_MAP_VERSION, INPUT_MAP_ID), InputEnums.REMAP_OPTION_ENABLED, // Use ESCAPE as reserved remapping key new[] { InputControls.Create( New[] { new Integer(AndroidKeyCode.KEYCODE_ESCAPE) }.ToJavaList(), new ArrayList<Integer>()) }.ToJavaList() );
InputMap فیلدهای زیر را دارد:
-
InputGroups: «گروههای ورودی» گزارششده توسط بازی شما. گروهها بهترتیب در رونهاد نمایش داده میشوند، مگراینکه گروههای درحال استفاده در تماسsetInputContext()مشخص شده باشد. -
MouseSettings: شیءMouseSettingsنشان میدهد که حساسیت موشواره قابل تنظیم است و موشواره در محور y معکوس است. -
InputMapId: شیءInputIdentifierکه شناسه عددی و نسخهInputMapرا ذخیره میکند (برای اطلاعات بیشتر، شناسههای کلید ردیابی را ببینید). -
InputRemappingOption: یکی ازInputEnums.REMAP_OPTION_ENABLEDیاInputEnums.REMAP_OPTION_DISABLED. تعیین میکند که آیا ویژگی تخصیص مجدد فعال است یا خیر. -
ReservedControls: فهرستی ازInputControlsکه کاربران اجازه ندارند به آنها تخصیص مجدد دهند.
شناسههای کلید پیگیری
InputAction، InputGroup، InputContext، و InputMap شیء حاوی شیء
InputIdentifier است که شناسه عددی یکتا و شناسه رشتهای را ذخیره میکند.
پیگیری نسخه رشتهای اشیای شما اختیاری است اما برای پیگیری نسخههای InputMap توصیه میشود. اگر نسخه رشتهای ارائه نشده باشد، رشته خالی است. نسخه رشتهای برای InputMap شیء الزامی است.
مثال زیر نسخه رشتهای را به InputActions یا
InputGroups اختصاص میدهد:
کاتلین
class InputSDKProviderKotlin : InputMappingProvider { companion object { const val INPUTMAP_VERSION = "1.0.0" private val enterMenuInputAction = InputAction.create( "Enter menu", InputControls.create(listOf(KeyEvent.KEYCODE_ENTER), emptyList()), InputIdentifier.create( INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal.toLong()), InputEnums.REMAP_OPTION_ENABLED ) private val movementInputGroup = InputGroup.create( "Basic movement", listOf( moveUpInputAction, moveLeftInputAction, moveDownInputAction, mouseGameInputAction), InputIdentifier.create( INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal.toLong()), InputEnums.REMAP_OPTION_ENABLED) } }
جاوا
public class InputSDKProvider implements InputMappingProvider { public static final String INPUTMAP_VERSION = "1.0.0"; private static final InputAction enterMenuInputAction = InputAction.create( "Enter menu", InputControls.create( Collections.singletonList(KeyEvent.KEYCODE_ENTER), Collections.emptyList()), InputIdentifier.create( INPUTMAP_VERSION, InputActionsIds.ENTER_MENU.ordinal()), InputEnums.REMAP_OPTION_ENABLED ); private static final InputGroup movementInputGroup = InputGroup.create( "Basic movement", Arrays.asList( moveUpInputAction, moveLeftInputAction, moveDownInputAction, moveRightInputAction, mouseGameInputAction ), InputIdentifier.create( INPUTMAP_VERSION, InputGroupsIds.BASIC_MOVEMENT.ordinal()), InputEnums.REMAP_OPTION_ENABLED ); }
C#
#if PLAY_GAMES_PC using Java.Lang; using Java.Util; using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel; public class InputSDKMappingProvider : InputMappingProviderCallbackHelper { public static readonly string INPUT_MAP_VERSION = "1.0.0"; private static readonly InputAction enterMenuInputAction = InputAction.Create( "Enter menu", InputControls.Create( new[] { new Integer(AndroidKeyCode.KEYCODE_SPACE)}.ToJavaList(), new ArrayList<Integer>()), InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputEventIds.ENTER_MENU), InputEnums.REMAP_OPTION_ENABLED ); private static readonly InputGroup movementInputGroup = InputGroup.Create( "Basic movement", new[] { moveUpInputAction, moveLeftInputAction, moveDownInputAction, moveRightInputAction, mouseGameInputAction }.ToJavaList(), InputIdentifier.Create( INPUT_MAP_VERSION, (long)InputGroupsIds.BASIC_MOVEMENT), InputEnums.REMAP_OPTION_ENABLED ); } #endif
شناسههای شماره InputAction شیء باید در همه InputActions در
InputMap شما یکتا باشد. بههمین ترتیب، شناسههای شیء InputGroup باید در همه
InputGroups در InputMap یکتا باشد. نمونه زیر نحوه استفاده از
enum برای ردیابی شناسههای یکتای شیء را نشان میدهد:
کاتلین
enum class InputActionsIds { NAVIGATE_UP, NAVIGATE_DOWN, ENTER_MENU, EXIT_MENU, // ... JUMP, RUN, EMOJI_1, EMOJI_2, // ... } enum class InputGroupsIds { // Main menu scene BASIC_NAVIGATION, // WASD, Enter, Backspace MENU_ACTIONS, // C: chat, Space: quick game, S: store // Gameplay scene BASIC_MOVEMENT, // WASD, space: jump, Shift: run MOUSE_ACTIONS, // Left click: shoot, Right click: aim EMOJIS, // Emojis with keys 1,2,3,4 and 5 GAME_ACTIONS, // M: map, P: pause, R: reload } enum class InputContextIds { MENU_SCENE, // Basic menu navigation, menu actions GAME_SCENE, // Basic movement, mouse actions, emojis, game actions } const val INPUT_MAP_ID = 0
جاوا
public enum InputActionsIds { NAVIGATE_UP, NAVIGATE_DOWN, ENTER_MENU, EXIT_MENU, // ... JUMP, RUN, EMOJI_1, EMOJI_2, // ... } public enum InputGroupsIds { // Main menu scene BASIC_NAVIGATION, // WASD, Enter, Backspace MENU_ACTIONS, // C: chat, Space: quick game, S: store // Gameplay scene BASIC_MOVEMENT, // WASD, space: jump, Shift: run MOUSE_ACTIONS, // Left click: shoot, Right click: aim EMOJIS, // Emojis with keys 1,2,3,4 and 5 GAME_ACTIONS, // M: map, P: pause, R: reload } public enum InputContextIds { MENU_SCENE, // Basic navigation, menu actions GAME_SCENE, // Basic movement, mouse actions, emojis, game actions } public static final long INPUT_MAP_ID = 0;
C#
public enum InputActionsIds { NAVIGATE_UP, NAVIGATE_DOWN, ENTER_MENU, EXIT_MENU, // ... JUMP, RUN, EMOJI_1, EMOJI_2, // ... } public enum InputGroupsIds { // Main menu scene BASIC_NAVIGATION, // WASD, Enter, Backspace MENU_ACTIONS, // C: chat, Space: quick game, S: store // Gameplay scene BASIC_MOVEMENT, // WASD, space: jump, Shift: run MOUSE_ACTIONS, // Left click: shoot, Right click: aim EMOJIS, // Emojis with keys 1,2,3,4 and 5 GAME_ACTIONS, // M: map, P: pause, R: reload } public enum InputContextIds { MENU_SCENE, // Basic navigation, menu actions GAME_SCENE, // Basic movement, mouse actions, emojis, game actions } public static readonly long INPUT_MAP_ID = 0;
InputIdentifier فیلدهای زیر را دارد:
UniqueId: شناسه عددی یکتایی که برای شناسایی واضح مجموعه معینی از دادههای ورودی بهصورت یکتا تنظیم شده است.-
VersionString: رشته نسخه قابلخواندن توسط انسان که برای شناسایی نسخه دادههای ورودی بین ۲ نسخه از تغییرات دادههای ورودی تنظیم شده است.
دریافت اعلان درباره رویدادهای تخصیص مجدد (اختیاری)
برای اطلاع از کلیدهای استفادهشده در بازیتان، اعلانهای رویدادهای تخصیص مجدد را دریافت کنید. این کار به بازی شما امکان میدهد داراییهای نشاندادهشده در صفحه بازی را که برای نمایش کنترلهای کنش استفاده میشود بهروز کند.
تصویر زیر نمونهای از این رفتار را نشان میدهد که در آن پساز تخصیص مجدد کلیدهای

این کارکرد با ثبت یک InputRemappingListener
کالبک بهدست میآید. برای پیادهسازی این ویژگی، ابتدا نمونه InputRemappingListener را ثبت کنید:
کاتلین
class InputSDKRemappingListener : InputRemappingListener { override fun onInputMapChanged(inputMap: InputMap) { Log.i(TAG, "Received update on input map changed.") if (inputMap.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { return } for (inputGroup in inputMap.inputGroups()) { if (inputGroup.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { continue } for (inputAction in inputGroup.inputActions()) { if (inputAction.inputRemappingOption() != InputEnums.REMAP_OPTION_DISABLED) { // Found InputAction remapped by user processRemappedAction(inputAction) } } } } private fun processRemappedAction(remappedInputAction: InputAction) { // Get remapped action info val remappedControls = remappedInputAction.remappedInputControls() val remappedKeyCodes = remappedControls.keycodes() val mouseActions = remappedControls.mouseActions() val version = remappedInputAction.inputActionId().versionString() val remappedActionId = remappedInputAction.inputActionId().uniqueId() val currentInputAction: Optional<InputAction> currentInputAction = if (version == null || version.isEmpty() || version == InputSDKProvider.INPUTMAP_VERSION ) { getCurrentVersionInputAction(remappedActionId) } else { Log.i(TAG, "Detected version of user-saved input action defers from current version") getCurrentVersionInputActionFromPreviousVersion( remappedActionId, version) } if (!currentInputAction.isPresent) { Log.e(TAG, String.format( "can't find remapped input action with id %d and version %s", remappedActionId, if (version == null || version.isEmpty()) "UNKNOWN" else version)) return } val originalControls = currentInputAction.get().inputControls() val originalKeyCodes = originalControls.keycodes() Log.i(TAG, String.format( "Found input action with id %d remapped from key %s to key %s", remappedActionId, keyCodesToString(originalKeyCodes), keyCodesToString(remappedKeyCodes))) // TODO: make display changes to match controls used by the user } private fun getCurrentVersionInputAction(inputActionId: Long): Optional<InputAction> { for (inputGroup in InputSDKProvider.gameInputMap.inputGroups()) { for (inputAction in inputGroup.inputActions()) { if (inputAction.inputActionId().uniqueId() == inputActionId) { return Optional.of(inputAction) } } } return Optional.empty() } private fun getCurrentVersionInputActionFromPreviousVersion( inputActionId: Long, previousVersion: String ): Optional<InputAction7gt; { // TODO: add logic to this method considering the diff between the current and previous // InputMap. return Optional.empty() } private fun keyCodesToString(keyCodes: List<Int>): String { val builder = StringBuilder() for (keyCode in keyCodes) { if (!builder.toString().isEmpty()) { builder.append(" + ") } builder.append(keyCode) } return String.format("(%s)", builder) } companion object { private const val TAG = "InputSDKRemappingListener" } }
جاوا
public class InputSDKRemappingListener implements InputRemappingListener { private static final String TAG = "InputSDKRemappingListener"; @Override public void onInputMapChanged(InputMap inputMap) { Log.i(TAG, "Received update on input map changed."); if (inputMap.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { return; } for (InputGroup inputGroup : inputMap.inputGroups()) { if (inputGroup.inputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { continue; } for (InputAction inputAction : inputGroup.inputActions()) { if (inputAction.inputRemappingOption() != InputEnums.REMAP_OPTION_DISABLED) { // Found InputAction remapped by user processRemappedAction(inputAction); } } } } private void processRemappedAction(InputAction remappedInputAction) { // Get remapped action info InputControls remappedControls = remappedInputAction.remappedInputControls(); List<Integer> remappedKeyCodes = remappedControls.keycodes(); List<Integer> mouseActions = remappedControls.mouseActions(); String version = remappedInputAction.inputActionId().versionString(); long remappedActionId = remappedInputAction.inputActionId().uniqueId(); Optional<InputAction> currentInputAction; if (version == null || version.isEmpty() || version.equals(InputSDKProvider.INPUTMAP_VERSION)) { currentInputAction = getCurrentVersionInputAction(remappedActionId); } else { Log.i(TAG, "Detected version of user-saved input action defers " + "from current version"); currentInputAction = getCurrentVersionInputActionFromPreviousVersion( remappedActionId, version); } if (!currentInputAction.isPresent()) { Log.e(TAG, String.format( "input action with id %d and version %s not found", remappedActionId, version == null || version.isEmpty() ? "UNKNOWN" : version)); return; } InputControls originalControls = currentInputAction.get().inputControls(); List<Integer> originalKeyCodes = originalControls.keycodes(); Log.i(TAG, String.format( "Found input action with id %d remapped from key %s to key %s", remappedActionId, keyCodesToString(originalKeyCodes), keyCodesToString(remappedKeyCodes))); // TODO: make display changes to match controls used by the user } private Optional<InputAction> getCurrentVersionInputAction( long inputActionId) { for (InputGroup inputGroup : InputSDKProvider.gameInputMap.inputGroups()) { for (InputAction inputAction : inputGroup.inputActions()) { if (inputAction.inputActionId().uniqueId() == inputActionId) { return Optional.of(inputAction); } } } return Optional.empty(); } private Optional<InputAction> getCurrentVersionInputActionFromPreviousVersion( long inputActionId, String previousVersion) { // TODO: add logic to this method considering the diff between your // current and previous InputMap. return Optional.empty(); } private String keyCodesToString(List<Integer> keyCodes) { StringBuilder builder = new StringBuilder(); for (Integer keyCode : keyCodes) { if (!builder.toString().isEmpty()) { builder.append(" + "); } builder.append(keyCode); } return String.format("(%s)", builder); } }
C#
#if PLAY_GAMES_PC using System.Text; using Java.Lang; using Java.Util; using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.Inputmapping.Datamodel; using UnityEngine; public class InputSDKRemappingListener : InputRemappingListenerCallbackHelper { public override void OnInputMapChanged(InputMap inputMap) { Debug.Log("Received update on remapped controls."); if (inputMap.InputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { return; } List<InputGroup> inputGroups = inputMap.InputGroups(); for (int i = 0; i < inputGroups.Size(); i ++) { InputGroup inputGroup = inputGroups.Get(i); if (inputGroup.InputRemappingOption() == InputEnums.REMAP_OPTION_DISABLED) { continue; } List<InputAction> inputActions = inputGroup.InputActions(); for (int j = 0; j < inputActions.Size(); j ++) { InputAction inputAction = inputActions.Get(j); if (inputAction.InputRemappingOption() != InputEnums.REMAP_OPTION_DISABLED) { // Found action remapped by user ProcessRemappedAction(inputAction); } } } } private void ProcessRemappedAction(InputAction remappedInputAction) { InputControls remappedInputControls = remappedInputAction.RemappedInputControls(); List<Integer> remappedKeycodes = remappedInputControls.Keycodes(); List<Integer> mouseActions = remappedInputControls.MouseActions(); string version = remappedInputAction.InputActionId().VersionString(); long remappedActionId = remappedInputAction.InputActionId().UniqueId(); InputAction currentInputAction; if (string.IsNullOrEmpty(version) || string.Equals( version, InputSDKMappingProvider.INPUT_MAP_VERSION)) { currentInputAction = GetCurrentVersionInputAction(remappedActionId); } else { Debug.Log("Detected version of used-saved input action defers" + " from current version"); currentInputAction = GetCurrentVersionInputActionFromPreviousVersion( remappedActionId, version); } if (currentInputAction == null) { Debug.LogError(string.Format( "Input Action with id {0} and version {1} not found", remappedActionId, string.IsNullOrEmpty(version) ? "UNKNOWN" : version)); return; } InputControls originalControls = currentInputAction.InputControls(); List<Integer> originalKeycodes = originalControls.Keycodes(); Debug.Log(string.Format( "Found Input Action with id {0} remapped from key {1} to key {2}", remappedActionId, KeyCodesToString(originalKeycodes), KeyCodesToString(remappedKeycodes))); // TODO: update HUD according to the controls of the user } private InputAction GetCurrentVersionInputAction( long inputActionId) { List<InputGroup> inputGroups = InputSDKMappingProvider.gameInputMap.InputGroups(); for (int i = 0; i < inputGroups.Size(); i++) { InputGroup inputGroup = inputGroups.Get(i); List<InputAction> inputActions = inputGroup.InputActions(); for (int j = 0; j < inputActions.Size(); j++) { InputAction inputAction = inputActions.Get(j); if (inputAction.InputActionId().UniqueId() == inputActionId) { return inputAction; } } } return null; } private InputAction GetCurrentVersionInputActionFromPreviousVersion( long inputActionId, string version) { // TODO: add logic to this method considering the diff between your // current and previous InputMap. return null; } private string KeyCodesToString(List<Integer> keycodes) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < keycodes.Size(); i ++) { Integer keycode = keycodes.Get(i); if (builder.Length > 0) { builder.Append(" + "); } builder.Append(keycode.IntValue()); } return string.Format("({0})", builder.ToString()); } } #endif
InputRemappingListener در زمان راهاندازی پساز بار کردن کنترلهای دوباره تخصیصدادهشده ذخیرهشده توسط کاربر، و پساز هر بار که کاربر کلیدهایش را دوباره تخصیص میدهد، مطلع میشود.
مقداردهی اولیه
اگر از InputContexts استفاده میکنید، بافت را در هر
گذار به صحنه جدید تنظیم کنید، ازجمله اولین بافتی که برای صحنه
اولیه استفاده شده است. پساز ثبت InputMap، باید InputContext را تنظیم کنید.
اگر از InputRemappingListeners برای دریافت اعلان درباره رویدادهای تخصیص مجدد استفاده میکنید،
InputRemappingListener را قبلاز ثبت InputMappingProvider ثبت کنید، درغیراینصورت ممکن است بازی شما رویدادهای مهم را درطول
زمان راهاندازی ازدست بدهد.
نمونه زیر نحوه مقداردهی اولیه API را نشان میدهد:
کاتلین
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (isGooglePlayGamesOnPC()) { val inputMappingClient = Input.getInputMappingClient(this) // Register listener before registering the provider inputMappingClient.registerRemappingListener(InputSDKRemappingListener()) inputMappingClient.setInputMappingProvider( InputSDKProvider()) // Set the context after you have registered the provider. inputMappingClient.setInputContext(InputSDKProvider.menuSceneInputContext) } }
جاوا
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (isGooglePlayGamesOnPC()) { InputMappingClient inputMappingClient = Input.getInputMappingClient(this); // Register listener before registering the provider inputMappingClient.registerRemappingListener( new InputSDKRemappingListener()); inputMappingClient.setInputMappingProvider( new InputSDKProvider()); // Set the context after you have registered the provider inputMappingClient.setInputContext(InputSDKProvider.menuSceneInputContext); } }
C#
#if PLAY_GAMES_PC using Google.Android.Libraries.Play.Games.Inputmapping; using Google.Android.Libraries.Play.Games.InputMapping.ExternalType.Android.Content; using Google.LibraryWrapper.Java; #endif public class GameManager : MonoBehaviour { #if PLAY_GAMES_PC private InputSDKMappingProvider _inputMapProvider = new InputSDKMappingProvider(); private InputMappingClient _inputMappingClient; #endif public void Awake() { #if PLAY_GAMES_PC Context context = (Context)Utils.GetUnityActivity().GetRawObject(); _inputMappingClient = Google.Android.Libraries.Play.Games.Inputmapping .Input.GetInputMappingClient(context); // Register listener before registering the provider. _inputMappingClient.RegisterRemappingListener( new InputSDKRemappingListener()); _inputMappingClient.SetInputMappingProvider(_inputMapProvider); // Register context after you have registered the provider. _inputMappingClient.SetInputContext( InputSDKMappingProvider.menuSceneInputContext); #endif } }
پاک کردن
وقتی بازیتان بسته میشود، نمونه InputMappingProvider و همه نمونههای InputRemappingListener را لغو ثبت کنید، اگرچه «کیت توسعه نرمافزار ورودی» بهاندازه کافی هوشمند است که درصورت انجام ندادن این کار، از نشت منابع جلوگیری کند:
کاتلین
override fun onDestroy() { if (isGooglePlayGamesOnPC()) { val inputMappingClient = Input.getInputMappingClient(this) inputMappingClient.clearInputMappingProvider() inputMappingClient.clearRemappingListener() } super.onDestroy() }
جاوا
@Override protected void onDestroy() { if (isGooglePlayGamesOnPC()) { InputMappingClient inputMappingClient = Input.getInputMappingClient(this); inputMappingClient.clearInputMappingProvider(); inputMappingClient.clearRemappingListener(); } super.onDestroy(); }
C#
public class GameManager : MonoBehaviour { private void OnDestroy() { #if PLAY_GAMES_PC _inputMappingClient.ClearInputMappingProvider(); _inputMappingClient.ClearRemappingListener(); #endif } }
آزمایش
میتوانید پیادهسازی «کیت توسعه نرمافزار ورودی» را با باز کردن دستی رونهاد برای مشاهده تجربه پخشکننده، یا ازطریق پوسته adb برای آزمایش و درستیسنجی خودکار آزمایش کنید.
«شبیهساز بازیهای Google Play در رایانه» صحت نقشه ورودی شما را دربرابر خطاهای رایج بررسی میکند. برای سناریوهایی مثل شناسههای یکتای تکراری، استفاده از
نقشههای ورودی مختلف، یا عدم موفقیت در قوانین تخصیص مجدد (اگر تخصیص مجدد فعال باشد)،
رونهاد پیام خطایی را بهصورت زیر نشان میدهد:

پیادهسازی «کیت توسعه نرمافزار ورودی» را بااستفاده از adb در خط فرمان درستیسنجی کنید.
برای دریافت نقشه ورودی فعلی، از فرمان adb shell زیر استفاده کنید (MY.PACKAGE.NAME را با نام بازیتان جایگزین کنید):
adb shell dumpsys input_mapping_service --get MY.PACKAGE.NAME
اگر InputMap را باموفقیت ثبت کرده باشید، بروندادی مشابه این خواهید دید:
Getting input map for com.example.inputsample...
Successfully received the following inputmap:
# com.google.android.libraries.play.games.InputMap@d73526e1
input_groups {
group_label: "Basic Movement"
input_actions {
action_label: "Jump"
input_controls {
keycodes: 51
keycodes: 19
}
unique_id: 0
}
input_actions {
action_label: "Left"
input_controls {
keycodes: 29
keycodes: 21
}
unique_id: 1
}
input_actions {
action_label: "Right"
input_controls {
keycodes: 32
keycodes: 22
}
unique_id: 2
}
input_actions {
action_label: "Use"
input_controls {
keycodes: 33
keycodes: 66
mouse_actions: MOUSE_LEFT_CLICK
mouse_actions_value: 0
}
unique_id: 3
}
}
input_groups {
group_label: "Special Input"
input_actions {
action_label: "Jump"
input_controls {
keycodes: 51
keycodes: 19
keycodes: 62
mouse_actions: MOUSE_LEFT_CLICK
mouse_actions_value: 0
}
unique_id: 4
}
input_actions {
action_label: "Duck"
input_controls {
keycodes: 47
keycodes: 20
keycodes: 113
mouse_actions: MOUSE_RIGHT_CLICK
mouse_actions_value: 1
}
unique_id: 5
}
}
mouse_settings {
allow_mouse_sensitivity_adjustment: true
invert_mouse_movement: true
}
بومیسازی
«کیت توسعه نرمافزار ورودی» از سیستم بومیسازی Android استفاده نمیکند. درنتیجه، هنگام ارسال InputMap باید رشتههای بومیسازیشده ارائه دهید. همچنین میتوانید از سیستم بومیسازی موتور بازیتان استفاده کنید.
Proguard
هنگام استفاده از Proguard برای کوچک کردن بازی، قوانین زیر را به فایل پیکربندی proguard اضافه کنید تا مطمئن شوید کیت توسعه نرمافزار از بسته نهایی شما حذف نمیشود:
-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }
قدم بعدی چیست
پساز ادغام «کیت توسعه نرمافزار ورودی» در بازیتان، میتوانید پیشنیازهای باقیمانده «بازیهای Google Play در رایانه» را تکمیل کنید. برای اطلاعات بیشتر، به شروع به کار با «بازیهای Google Play در رایانه» مراجعه کنید.