เอกสารนี้อธิบายวิธีตั้งค่าและแสดง Input SDK ในเกมที่รองรับ Google Play Games บน PC ซึ่งรวมถึงการเพิ่ม SDK ลงในเกมและสร้างแผนที่อินพุตซึ่งมีการกำหนดค่าการดําเนินการของเกมไปยังอินพุตของผู้ใช้
ก่อนเริ่มต้นใช้งาน
ก่อนเพิ่ม Input SDK ลงในเกม คุณต้องรองรับการป้อนข้อมูลแป้นพิมพ์และเมาส์โดยใช้ระบบการป้อนข้อมูลของเครื่องมือสร้างเกม
Input SDK จะส่งข้อมูลเกี่ยวกับการควบคุมที่เกมของคุณใช้ให้กับ Google Play Games บน PC เพื่อให้แสดงการควบคุมดังกล่าวต่อผู้ใช้ได้ และยังอนุญาตให้ผู้ใช้เปลี่ยนการแมปแป้นพิมพ์ได้อีกด้วย (ไม่บังคับ)
การควบคุมแต่ละรายการคือ InputAction
(เช่น "J" สำหรับ "Jump") และคุณจัดระเบียบ InputActions
เป็น InputGroups
InputGroup
อาจแสดงถึงโหมดอื่นในเกม เช่น "การขับรถ" หรือ "การเดิน" หรือ "เมนูหลัก" นอกจากนี้ คุณยังใช้ InputContexts
เพื่อระบุว่ากลุ่มใดมีการใช้งานในแต่ละจุดของเกมได้ด้วย
คุณสามารถเปิดใช้การแมปแป้นพิมพ์ใหม่โดยอัตโนมัติได้ แต่หากต้องการระบุอินเทอร์เฟซการแมปการควบคุมใหม่ของคุณเอง คุณสามารถปิดใช้การแมป Input SDK ได้
แผนภาพลำดับต่อไปนี้อธิบายวิธีการทำงานของ API ของ Input SDK
เมื่อเกมของคุณใช้ Input SDK ตัวควบคุมจะปรากฏในวางซ้อนของ Google Play Games บน PC
การซ้อนทับ Google Play Games บน PC
การวางซ้อนของ Google Play Games บน PC ("การวางซ้อน") จะแสดงการควบคุมที่เกมของคุณกำหนด ผู้ใช้เข้าถึงการวางซ้อนได้ทุกเมื่อโดยกด Shift + Tab
แนวทางปฏิบัติแนะนำในการออกแบบการเชื่อมโยงแป้นพิมพ์
เมื่อออกแบบการเชื่อมโยงแป้นพิมพ์ ให้พิจารณาแนวทางปฏิบัติแนะนำต่อไปนี้
- จัดกลุ่ม
InputActions
ออกเป็นInputGroups
ที่เกี่ยวข้องตามตรรกะเพื่อปรับปรุงการไปยังส่วนต่างๆ และการค้นพบตัวควบคุมในระหว่างเกมเพลย์ - กำหนด
InputGroup
แต่ละรายการให้กับInputContext
ไม่เกิน 1 รายการInputMap
แบบละเอียดช่วยให้คุณไปยังส่วนต่างๆ ของการควบคุมในวางซ้อนได้ดีขึ้น - สร้าง
InputContext
สำหรับฉากแต่ละประเภทของเกม โดยทั่วไป คุณสามารถใช้InputContext
รายการเดียวสำหรับฉาก "เหมือนเมนู" ทั้งหมด ใช้InputContexts
ที่แตกต่างกันสำหรับมินิเกมในเกมหรือสำหรับการควบคุมทางเลือกสำหรับฉากเดียว - หากการดําเนินการ 2 รายการออกแบบมาเพื่อใช้คีย์เดียวกันภายใต้
InputContext
เดียวกัน ให้ใช้สตริงป้ายกํากับ เช่น "โต้ตอบ / เรียกใช้" - หากออกแบบปุ่ม 2 ปุ่มให้เชื่อมโยงกับ
InputAction
เดียวกัน ให้ใช้InputActions
2 ตัวที่แตกต่างกันซึ่งทําการกระทําเดียวกันในเกม คุณสามารถใช้สตริงป้ายกำกับเดียวกันสำหรับทั้งInputActions
แต่รหัสของInputActions
จะต้องแตกต่างกัน - หากใช้แป้นกดร่วมกับชุดแป้น ให้พิจารณาใช้
InputAction
1 ตัวที่มีแป้นกดร่วมแทนInputAction
หลายตัวที่รวมแป้นกดร่วม (เช่น ใช้ Shift และ W, A, S, D แทน Shift + W, Shift + A, Shift + S, Shift + D)InputActions
- การแมปอินพุตใหม่จะปิดอยู่โดยอัตโนมัติเมื่อผู้ใช้เขียนในช่องข้อความ ทำตามแนวทางปฏิบัติแนะนำในการใช้ช่องข้อความของ Android เพื่อให้ Android ตรวจหาช่องข้อความในเกมได้ และป้องกันไม่ให้แป้นที่แมปใหม่รบกวนช่องข้อความ หากเกมของคุณต้องใช้ช่องข้อความที่ไม่ใช่แบบดั้งเดิม คุณสามารถใช้
setInputContext()
ที่มีInputContext
ซึ่งมีรายการInputGroups
ว่างเพื่อปิดใช้การแมปใหม่ด้วยตนเอง - หากเกมรองรับการแมปใหม่ ให้พิจารณาอัปเดตการเชื่อมโยงแป้นพิมพ์เป็นการดำเนินการที่มีความละเอียดอ่อนซึ่งอาจขัดแย้งกับเวอร์ชันที่ผู้ใช้บันทึกไว้ หลีกเลี่ยงการเปลี่ยนรหัสของการควบคุมที่มีอยู่ หากเป็นไปได้
ฟีเจอร์การแมปใหม่
Google Play Games บน PC รองรับการแมปการควบคุมด้วยแป้นพิมพ์ใหม่ตามการเชื่อมโยงแป้นพิมพ์ที่เกมของคุณระบุโดยใช้ Input SDK คุณจะเลือกหรือไม่เลือกก็ได้และปิดใช้ทั้งหมดได้ เช่น คุณอาจต้องการระบุอินเทอร์เฟซการแมปแป้นพิมพ์ใหม่ของคุณเอง หากต้องการปิดใช้การแมปใหม่สำหรับเกม เพียงระบุตัวเลือกการแมปใหม่ซึ่งปิดใช้สำหรับ InputMap
(ดูข้อมูลเพิ่มเติมที่หัวข้อสร้าง InputMap)
หากต้องการเข้าถึงฟีเจอร์นี้ ผู้ใช้ต้องเปิดการวางซ้อน แล้วคลิกการดำเนินการที่ต้องการแมปใหม่ หลังจากเหตุการณ์การแมปใหม่ทุกครั้ง Google Play Games บน PC จะแมปการควบคุมแต่ละรายการที่ผู้ใช้แมปใหม่เป็นการควบคุมเริ่มต้นที่เกมของคุณคาดหวังว่าจะได้รับ ดังนั้นเกมของคุณจึงไม่จำเป็นต้องรับรู้ถึงการแมปใหม่ของผู้เล่น คุณอัปเดตชิ้นงานที่ใช้สําหรับแสดงการควบคุมด้วยแป้นพิมพ์ในเกมได้ (ไม่บังคับ) โดยการเพิ่ม Callback สําหรับการแมปเหตุการณ์ใหม่
Google Play Games บน PC จะจัดเก็บการควบคุมที่แมปใหม่ไว้ในเครื่องสำหรับผู้ใช้แต่ละราย ซึ่งช่วยให้การควบคุมคงที่ตลอดเซสชันการเล่นเกม ระบบจะจัดเก็บข้อมูลนี้ไว้ในดิสก์สำหรับแพลตฟอร์ม PC เท่านั้น และจะไม่ส่งผลต่อประสบการณ์การใช้งานบนอุปกรณ์เคลื่อนที่ ระบบจะลบข้อมูลการควบคุมเมื่อผู้ใช้ถอนการติดตั้งหรือติดตั้ง Google Play Games บน PC อีกครั้ง ข้อมูลนี้จะไม่คงอยู่ในอุปกรณ์ PC หลายเครื่อง
โปรดหลีกเลี่ยงข้อจำกัดต่อไปนี้เพื่อรองรับฟีเจอร์การแมปใหม่ในเกม
ข้อจํากัดของการแมปใหม่
ฟีเจอร์การแมปใหม่จะปิดใช้ในเกมได้หากการเชื่อมโยงแป้นพิมพ์มีกรณีต่อไปนี้
InputActions
แบบหลายแป้นที่ไม่ได้ประกอบด้วยแป้นกดร่วม + แป้นที่ไม่ใช่แป้นกดร่วม เช่น Shift + A ใช้ได้ แต่ A + B, Ctrl + Alt หรือ Shift + A + Tab ใช้ไม่ได้InputMap
มีInputActions
,InputGroups
หรือInputContexts
ที่มีรหัสที่ไม่ซ้ำกันซ้ำ
ข้อจํากัดของการแมปใหม่
เมื่อออกแบบการเชื่อมโยงแป้นพิมพ์สำหรับการแมปใหม่ ให้พิจารณาข้อจำกัดต่อไปนี้
- ระบบไม่รองรับการแมปใหม่เป็นชุดแป้นที่กดร่วมกัน ตัวอย่างเช่น ผู้ใช้จะไม่สามารถกำหนดค่าใหม่สำหรับ Shift + A เป็น Ctrl + B หรือ A เป็น Shift + A
- แป้น
InputActions
ที่ใช้กับปุ่มเมาส์ไม่รองรับการแมปใหม่ เช่น Shift + คลิกขวา จะแมปใหม่ไม่ได้
ทดสอบการแมปแป้นใหม่ใน Google Play Games บนโปรแกรมจำลอง PC
คุณเปิดใช้ฟีเจอร์การแมปใหม่ใน Google Play Games บนโปรแกรมจำลอง PC ได้ทุกเมื่อโดยออกคำสั่ง adb ต่อไปนี้
adb shell dumpsys input_mapping_service --set RemappingFlagValue true
การเปลี่ยนแปลงการวางซ้อนจะเหมือนกับในรูปภาพต่อไปนี้
เพิ่ม SDK
ติดตั้ง Input SDK ตามแพลตฟอร์มการพัฒนาของคุณ
Java และ Kotlin
รับ Input SDK สําหรับ Java หรือ Kotlin โดยเพิ่มการพึ่งพาในไฟล์ build.gradle
ระดับโมดูล ดังนี้
dependencies {
implementation 'com.google.android.libraries.play.games:inputmapping:1.1.1-beta'
...
}
Unity
Input SDK เป็นแพ็กเกจ Unity มาตรฐานที่มี Dependency หลายรายการ
คุณต้องติดตั้งแพ็กเกจพร้อมกับข้อกำหนดทั้งหมด การติดตั้งแพ็กเกจทำได้หลายวิธี
ติดตั้ง .unitypackage
ดาวน์โหลดไฟล์ UnityPackage ของ Input SDK
พร้อมทรัพยากร Dependency ทั้งหมด คุณติดตั้ง .unitypackage
ได้โดยเลือกเนื้อหา > นําเข้าแพ็กเกจ > แพ็กเกจที่กําหนดเอง แล้วค้นหาไฟล์ที่ดาวน์โหลด
ติดตั้งโดยใช้ UPM
หรือจะติดตั้งแพ็กเกจโดยใช้ Unity Package Manager ก็ได้ โดยดาวน์โหลด .tgz
และติดตั้ง Dependency ดังนี้
- 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
Kotlin
class InputSDKProvider : InputMappingProvider { override fun onProvideInputMap(): InputMap { TODO("Not yet implemented") } }
Java
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
ทั้งหมด แต่ Input SDK ฉลาดพอที่จะปิดการแมปใหม่หากคุณไม่รองรับใน InputMap
ตัวอย่างนี้จะแมปแป้น
Kotlin
companion object { private val driveInputAction = InputAction.create( "Drive", InputActionsIds.DRIVE.ordinal.toLong(), InputControls.create(listOf(KeyEvent.KEYCODE_SPACE), emptyList()), InputEnums.REMAP_OPTION_ENABLED) }
Java
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 );
การดำเนินการยังแสดงอินพุตเมาส์ได้ด้วย ตัวอย่างนี้จะตั้งค่าการคลิกซ้ายเป็นการดำเนินการย้าย
Kotlin
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) }
Java
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
ในตัวอย่างนี้
Kotlin
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) }
Java
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 );
Input SDK ช่วยให้คุณผสมปุ่มเมาส์และปุ่มแป้นพิมพ์เข้าด้วยกันเพื่อดำเนินการแบบครั้งเดียวได้ ตัวอย่างนี้ระบุว่าการกด
Kotlin
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) }
Java
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
: สตริงที่แสดงใน UI เพื่อแสดงการดำเนินการนี้ การทำให้เป็นเวอร์ชันแปลจะไม่ทำโดยอัตโนมัติ ดังนั้นให้ทำเวอร์ชันแปลตั้งแต่เนิ่นๆInputControls
: กำหนดการควบคุมอินพุตที่การดำเนินการนี้ใช้ โดยตัวควบคุมจะแมปกับสัญลักษณ์ที่สอดคล้องกันในการวางซ้อนInputActionId
: ออบเจ็กต์InputIdentifier
ที่เก็บรหัสตัวเลขและเวอร์ชันของInputAction
(ดูข้อมูลเพิ่มเติมในรหัสคีย์การติดตาม)InputRemappingOption
: เป็นหนึ่งในInputEnums.REMAP_OPTION_ENABLED
หรือInputEnums.REMAP_OPTION_DISABLED
กําหนดว่าเปิดใช้การดําเนินการเพื่อเปลี่ยนเส้นทางหรือไม่ หากเกมไม่รองรับการแมปใหม่ คุณสามารถข้ามช่องนี้หรือเพียงแค่ตั้งค่าให้ปิดใช้RemappedInputControls
: ออบเจ็กต์InputControls
แบบอ่านอย่างเดียวที่ใช้อ่านคีย์ที่แมปใหม่ซึ่งผู้ใช้ตั้งค่าไว้ในการแมปเหตุการณ์ใหม่ (ใช้สำหรับการแจ้งเตือนเกี่ยวกับการแมปเหตุการณ์ใหม่)
InputControls
แสดงอินพุตที่เชื่อมโยงกับการดำเนินการและมีฟิลด์ต่อไปนี้
AndroidKeycodes
: คือรายการจำนวนเต็มซึ่งแสดงการป้อนข้อมูลแป้นพิมพ์ที่เชื่อมโยงกับการดำเนินการ ซึ่งจะกำหนดไว้ในคลาส KeyEvent หรือคลาส AndroidKeycode สำหรับ UnityMouseActions
: คือรายการค่าMouseAction
ที่แสดงอินพุตของเมาส์ซึ่งเชื่อมโยงกับการดำเนินการนี้
กําหนดกลุ่มอินพุต
InputActions
จะจัดกลุ่มไว้กับการดําเนินการที่เชื่อมโยงกันตามตรรกะโดยใช้ InputGroups
เพื่อปรับปรุงการนําทางและการควบคุมการค้นพบในการวางซ้อน รหัสInputGroup
แต่ละรหัสต้องไม่ซ้ำกันสำหรับInputGroups
ทั้งหมดในเกม
การจัดระเบียบการดําเนินการของอินพุตเป็นกลุ่มจะช่วยให้ผู้เล่นค้นหาการเชื่อมโยงคีย์ที่ถูกต้องสําหรับบริบทปัจจุบันได้ง่ายขึ้น
หากรองรับการแมปใหม่ คุณสามารถกำหนดว่า InputGroups
ใดบ้างที่ทำการแมปใหม่ได้ หากเกมไม่รองรับการแมปใหม่ คุณควรตั้งค่าตัวเลือกการแมปใหม่เป็นปิดสำหรับ InputGroups
ทั้งหมด แต่ Input SDK ฉลาดพอที่จะปิดการแมปใหม่หากคุณไม่รองรับใน InputMap
Kotlin
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 ) }
Java
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()
เพื่อตั้งค่าบริบททุกครั้งที่เกมเข้าสู่ฉากอื่น รูปภาพต่อไปนี้แสดงลักษณะการทํางานนี้ ในฉาก "ขับรถ" การดำเนินการการควบคุมถนนจะแสดงที่ด้านบนของการวางซ้อน เมื่อเปิดเมนู "Store" การดำเนินการ "การควบคุมเมนู" จะแสดงที่ด้านบนของการวางซ้อน
การอัปเดตการวางซ้อนเหล่านี้ทำได้โดยการตั้งค่า InputContext
ที่แตกต่างกัน ณ จุดต่างๆ ในเกม หากต้องการทำสิ่งต่อไปนี้
- จัดกลุ่ม
InputActions
กับการดำเนินการที่เกี่ยวข้องตามตรรกะโดยใช้InputGroups
- กำหนด
InputGroups
เหล่านี้ให้กับInputContext
สำหรับส่วนต่างๆ ของเกม
InputGroups
ที่อยู่ในInputContext
เดียวกันต้องไม่ขัดแย้งกัน
InputActions
ที่ใช้คีย์เดียวกัน แนวทางปฏิบัติแนะนำคือให้กําหนด InputGroup
แต่ละรายการให้กับ InputContext
รายการเดียว
โค้ดตัวอย่างต่อไปนี้แสดงตรรกะ InputContext
Kotlin
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)) }
Java
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
Kotlin
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())) ) }
Java
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
: InputGroups ที่เกมของคุณรายงาน กลุ่มจะแสดงตามลําดับในวางซ้อน เว้นแต่จะมีการระบุกลุ่มปัจจุบันที่ใช้การโทรsetInputContext()
MouseSettings
: ออบเจ็กต์MouseSettings
บ่งบอกว่าสามารถปรับความไวของเมาส์ได้ และมีการกลับค่าของเมาส์บนแกน yInputMapId
: ออบเจ็กต์InputIdentifier
ที่เก็บรหัสหมายเลขและเวอร์ชันของInputMap
(ดูข้อมูลเพิ่มเติมในรหัสคีย์การติดตาม)InputRemappingOption
: เป็นหนึ่งในInputEnums.REMAP_OPTION_ENABLED
หรือInputEnums.REMAP_OPTION_DISABLED
กำหนดว่าเปิดใช้ฟีเจอร์การแมปใหม่หรือไม่ReservedControls
: รายการInputControls
ที่ผู้ใช้ไม่ได้รับอนุญาตให้แมปใหม่
รหัสคีย์ติดตาม
ออบเจ็กต์ InputAction
, InputGroup
, InputContext
และ InputMap
ประกอบด้วยออบเจ็กต์ InputIdentifier
ที่เก็บรหัสตัวเลขที่ไม่ซ้ำกันและรหัสเวอร์ชันสตริง
การติดตามเวอร์ชันสตริงของออบเจ็กต์เป็นตัวเลือกที่ไม่บังคับ แต่เราขอแนะนําให้ติดตามเวอร์ชันของ InputMap
หากไม่ได้ระบุเวอร์ชันสตริง สตริงจะว่างเปล่า ต้องระบุเวอร์ชันสตริงสำหรับออบเจ็กต์ InputMap
ตัวอย่างต่อไปนี้กําหนดเวอร์ชันสตริงให้กับ InputActions
หรือ
InputGroups
Kotlin
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) } }
Java
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
เพื่อติดตามรหัสที่ไม่ซ้ำกันของออบเจ็กต์
Kotlin
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
Java
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
: สตริงเวอร์ชันที่มนุษย์อ่านได้ซึ่งตั้งค่าเพื่อระบุเวอร์ชันของข้อมูลอินพุตระหว่างการเปลี่ยนแปลงข้อมูลอินพุต 2 เวอร์ชัน
รับการแจ้งเตือนเกี่ยวกับการแมปเหตุการณ์ใหม่ (ไม่บังคับ)
รับการแจ้งเตือนเกี่ยวกับเหตุการณ์การแมปใหม่เพื่อทราบถึงแป้นที่ใช้ในเกม ซึ่งจะช่วยให้เกมอัปเดตชิ้นงานที่แสดงบนหน้าจอเกมเพื่อใช้แสดงการควบคุมการดําเนินการได้
รูปภาพต่อไปนี้แสดงตัวอย่างลักษณะการทำงานนี้หลังจากที่แมปแป้น
ฟังก์ชันนี้จะทํางานได้โดยการลงทะเบียน InputRemappingListener
callback หากต้องการใช้ฟีเจอร์นี้ ให้เริ่มด้วยการลงทะเบียนอินสแตนซ์ InputRemappingListener
โดยทำดังนี้
Kotlin
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" } }
Java
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
ให้ตั้งค่าบริบทในการเปลี่ยนแต่ละฉากเป็นฉากใหม่ รวมถึงบริบทแรกที่ใช้กับฉากเริ่มต้น คุณต้องตั้งค่า InputContext
หลังจากที่ลงทะเบียน InputMap
แล้ว
หากคุณใช้ InputRemappingListeners
เพื่อรับการแจ้งเตือนเกี่ยวกับการแมปเหตุการณ์ใหม่ ให้ลงทะเบียน InputRemappingListener
ก่อนลงทะเบียน InputMappingProvider
ไม่เช่นนั้นเกมอาจพลาดเหตุการณ์สำคัญในช่วงเวลาเปิดตัว
ตัวอย่างต่อไปนี้แสดงวิธีเริ่มต้น API
Kotlin
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) } }
Java
@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
ทั้งหมดเมื่อปิดเกม แม้ว่า Input SDK จะฉลาดพอที่จะหลีกเลี่ยงการเปิดเผยทรัพยากรหากคุณไม่ได้ดำเนินการดังนี้
Kotlin
override fun onDestroy() { if (isGooglePlayGamesOnPC()) { val inputMappingClient = Input.getInputMappingClient(this) inputMappingClient.clearInputMappingProvider() inputMappingClient.clearRemappingListener() } super.onDestroy() }
Java
@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 } }
ทดสอบ
คุณสามารถทดสอบการติดตั้งใช้งาน Input SDK ได้โดยเปิดการวางซ้อนด้วยตนเองเพื่อดูประสบการณ์การใช้งานเพลเยอร์ หรือผ่านเชลล์ adb เพื่อทำการทดสอบและการยืนยันอัตโนมัติ
โปรแกรมจำลอง Google Play Games บน PC จะตรวจสอบความถูกต้องของแผนที่อินพุตเทียบกับข้อผิดพลาดที่พบบ่อย สำหรับสถานการณ์ต่างๆ เช่น การใช้รหัสที่ไม่ซ้ำกันซ้ำกัน การใช้แผนที่อินพุตที่แตกต่างกัน หรือกฎการแมปใหม่ไม่สำเร็จ (หากเปิดใช้การแมปใหม่) ภาพซ้อนทับจะแสดงข้อความแสดงข้อผิดพลาดดังต่อไปนี้
ยืนยันการติดตั้งใช้งาน Input SDK โดยใช้ 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
}
การแปล
Input SDK ไม่ได้ใช้ระบบแปลภาษาของ Android คุณจึงต้องระบุสตริงที่แปลแล้วเมื่อส่ง InputMap
คุณยังใช้ระบบแปลภาษาของเกมเอนจินได้ด้วย
Proguard
เมื่อใช้ Proguard เพื่อย่อขนาดเกม ให้เพิ่มกฎต่อไปนี้ลงในไฟล์การกําหนดค่า Proguard เพื่อให้แน่ใจว่าระบบจะไม่นํา SDK ออกจากแพ็กเกจสุดท้าย
-keep class com.google.android.libraries.play.hpe.** { *; }
-keep class com.google.android.libraries.play.games.inputmapping.** { *; }
ขั้นต่อไปคืออะไร
หลังจากผสานรวม Input SDK เข้ากับเกมแล้ว คุณจะปฏิบัติตามข้อกำหนดที่เหลือของ Google Play Games บน PC ต่อได้ ดูข้อมูลเพิ่มเติมได้ที่เริ่มต้นใช้งาน Google Play Games บน PC