เริ่มต้นใช้งาน Input SDK

เอกสารนี้อธิบายวิธีตั้งค่าและแสดงอินพุต SDK ใน เกมที่รองรับ Google Play Games บน PC งานดังกล่าวรวมถึงการเพิ่ม SDK เกมของคุณ และสร้างแผนที่อินพุตที่มี การกำหนดการดำเนินการในเกมแก่ผู้ใช้

ก่อนเริ่มต้นใช้งาน

ก่อนที่จะเพิ่มอินพุต SDK ลงในเกม คุณต้องรองรับ แป้นพิมพ์และเมาส์โดยใช้ ระบบอินพุต

Input SDK ให้ข้อมูลเกี่ยวกับ Google Play Games บน PC สิ่งที่เกมของคุณใช้ควบคุม เพื่อแสดงต่อผู้ใช้ นอกจากนี้ยังสามารถ มีตัวเลือกให้ผู้ใช้รีแมปแป้นพิมพ์ได้

ตัวควบคุมแต่ละตัวคือ InputAction (เช่น "J" สําหรับ "Jump") และคุณจัดระเบียบ InputActions ไปยัง InputGroups InputGroup อาจแสดงถึง ในเกมของคุณ เช่น "ขับรถ" หรือ "เดินเท้า" หรือ "เมนูหลัก" นอกจากนี้คุณยัง ใช้ InputContexts เพื่อระบุว่ากลุ่มใดมีการใช้งาน ณ จุดต่างๆ ของ เกมนี้

คุณสามารถเปิดใช้การรีแมปแป้นพิมพ์ให้คุณโดยอัตโนมัติ แต่ถ้า คุณต้องการให้มีอินเทอร์เฟซการรีแมปการควบคุมของคุณเอง คุณก็สามารถปิดใช้ การแมป SDK อินพุตใหม่

แผนภาพลำดับต่อไปนี้อธิบายวิธีการทำงานของ API ของอินพุต SDK

แผนภาพลำดับของการใช้งานเกมที่เรียกใช้ Input SDK API
และการโต้ตอบกับ Android
อุปกรณ์

เมื่อเกมใช้ SDK อินพุต ตัวควบคุมของคุณจะปรากฏขึ้น ในการวางซ้อน Google Play Games บน PC

การวางซ้อน Google Play Games บน PC

การวางซ้อน Google Play Games บน PC ("การวางซ้อน") จะแสดงตัวควบคุม ที่กำหนดโดยเกมของคุณ ผู้ใช้เข้าถึงการวางซ้อนได้ตลอดเวลาโดย กด Shift + Tab

การวางซ้อน Google Play Games บน PC

แนวทางปฏิบัติแนะนำสำหรับการออกแบบการเชื่อมโยงคีย์

โปรดพิจารณาแนวทางปฏิบัติแนะนำต่อไปนี้เมื่อออกแบบการเชื่อมโยงคีย์

  • จัดกลุ่ม InputActions เป็น InputGroups ที่มีความเกี่ยวข้องทางตรรกะเพื่อปรับปรุง การนำทางและการค้นพบได้ของตัวควบคุมระหว่างการเล่นเกม
  • กำหนด InputGroup แต่ละรายการให้กับ InputContext ไม่เกิน 1 รายการ เม็ดเล็กละเอียด InputMap ส่งผลให้ประสบการณ์การใช้งานที่ดีขึ้นสำหรับการนำทางตัวควบคุมใน การซ้อนทับ
  • สร้าง InputContext สำหรับฉากแต่ละประเภทของเกม โดยปกติแล้ว คุณจะใช้ InputContext รายการเดียวสำหรับ "เมนูแบบเมนู" ทั้งหมดก็ได้ ต่างๆ ใช้InputContextsที่แตกต่างกันสำหรับมินิเกมในเกมหรือสำหรับ การควบคุมสำรองสำหรับฉากเดียว
  • หากการดำเนินการ 2 รายการได้รับการออกแบบมาให้ใช้คีย์เดียวกันภายใต้ InputContext ใช้สตริงป้ายกำกับ เช่น "โต้ตอบ / เริ่มทำงาน"
  • หาก 2 แป้นได้รับการออกแบบมาเพื่อเชื่อมโยงกับ InputAction เดียวกัน ให้ใช้ 2 InputActions ที่แตกต่างกันที่ทำงานเดียวกันในเกม คุณสามารถ ใช้สตริงป้ายกำกับเดียวกันสำหรับ InputActions ทั้ง 2 รายการ แต่รหัสต้องเป็น แตกต่างกัน
  • หากมีการใช้แป้นกดร่วมกับชุดแป้น ให้พิจารณาใช้แป้นเดียว InputAction โดยใช้แป้นกดร่วม แทนที่จะเป็น InputActions หลายรายการที่ รวมคีย์ตัวปรับแต่ง (เช่น ใช้ Shift และ W, A, S, D แทน Shift + W, Shift + A, Shift + S, Shift + D)
  • ระบบจะปิดใช้การแมปอินพุตใหม่โดยอัตโนมัติเมื่อผู้ใช้เขียนลงในข้อความ ด้วย ทำตามแนวทางปฏิบัติแนะนำสำหรับการใช้ช่องข้อความ Android ว่า Android สามารถตรวจหาช่องข้อความในเกมและป้องกันไม่ให้มีคีย์ที่รีแมปได้ ไม่ให้รบกวนพวกเขาได้ หากเกมของคุณต้องใช้ข้อความที่ไม่เป็นไปตามรูปแบบ ฟิลด์ที่คุณสามารถใช้ setInputContext() กับ InputContext ที่มีเอลิเมนต์ รายการว่างของ InputGroups เพื่อปิดใช้การรีแมปด้วยตนเอง
  • หากเกมของคุณรองรับการรีแมป ให้ลองอัปเดตการเชื่อมโยงคีย์ การดำเนินการที่มีความละเอียดอ่อนซึ่งขัดแย้งกับเวอร์ชันที่ผู้ใช้บันทึกไว้ หลีกเลี่ยง เปลี่ยนรหัสของตัวควบคุมที่มีอยู่ เมื่อเป็นไปได้

ฟีเจอร์การรีแมป

Google Play Games บน PC รองรับการรีแมปการควบคุมแป้นพิมพ์โดยอิงตามแป้น การเชื่อมโยงเกมที่คุณให้โดยใช้ SDK อินพุต ขั้นตอนนี้เป็นแบบไม่บังคับและ สามารถปิดใช้ได้ทั้งหมด เช่น คุณอาจต้องให้มีแป้นพิมพ์ของคุณเอง การรีแมปอินเทอร์เฟซ หากต้องการปิดใช้การรีแมปสำหรับเกม คุณเพียงแค่ต้องระบุ ตัวเลือกการรีแมปถูกปิดใช้งานสำหรับ InputMap ของคุณ (โปรดดู สร้าง InputMap สําหรับข้อมูลเพิ่มเติม)

ในการเข้าถึงฟีเจอร์นี้ ผู้ใช้ต้องเปิดการวางซ้อนแล้วคลิกการทำงาน ที่ต้องการรีแมป หลังจากทุกกิจกรรมรีแมป Google Play Games บน PC แมป ตัวควบคุมแต่ละรายการที่ผู้ใช้รีแมปไปเป็นการควบคุมเริ่มต้นที่เกมของคุณคาดว่าจะทำ เพื่อให้เกมของคุณไม่จำเป็นต้องรับรู้ถึงการรีแมปของผู้เล่น คุณ สามารถเลือกอัปเดตเนื้อหาที่ใช้แสดงตัวควบคุมแป้นพิมพ์ใน เกมได้โดยการเพิ่ม Callback สำหรับรีแมปเหตุการณ์

ลองรีแมปคีย์

Google Play Games บน PC จะจัดเก็บการควบคุมที่รีแมปในเครื่องของผู้ใช้แต่ละคน เปิดใช้งานการควบคุมอย่างต่อเนื่องในเซสชันการเล่นเกม ระบบจัดเก็บข้อมูลนี้ไว้ บนดิสก์เท่านั้นสำหรับแพลตฟอร์ม PC และจะไม่ส่งผลต่อประสบการณ์การใช้งานบนอุปกรณ์เคลื่อนที่ โดยข้อมูลการควบคุมจะถูกลบเมื่อผู้ใช้ถอนการติดตั้งหรือติดตั้ง Google Play Games บน PC อีกครั้ง โดยข้อมูลนี้จะไม่คงอยู่ในอุปกรณ์ PC หลายเครื่อง

โปรดหลีกเลี่ยงข้อจำกัดต่อไปนี้เพื่อรองรับฟีเจอร์การรีแมปในเกม

ข้อจำกัดของการรีแมป

คุณปิดใช้ฟีเจอร์การรีแมปในเกมได้ หากการเชื่อมโยงแป้นมี กรณีต่อไปนี้

  • InputActions หลายคีย์ที่ไม่ได้เขียนด้วยแป้นกดร่วม + a ไม่มีตัวแก้ไข ตัวอย่างเช่น 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

ติดตั้งอินพุต SDK ตามแพลตฟอร์มการพัฒนาของคุณ

Java และ Kotlin

รับอินพุต SDK สำหรับ Java หรือ Kotlin โดยการเพิ่ม Dependency ไปยัง ไฟล์ build.gradle ระดับโมดูล:

dependencies {
  implementation 'com.google.android.libraries.play.games:inputmapping:1.1.0-beta'
  ...
}

เอกภาพ

Input SDK เป็นแพ็กเกจ Unity มาตรฐานที่มีทรัพยากร Dependency หลายรายการ

จำเป็นต้องติดตั้งแพ็กเกจที่มีการอ้างอิงทั้งหมด ซึ่งทำได้หลายวิธี เพื่อติดตั้งแพ็กเกจ

ติดตั้ง .unitypackage

ดาวน์โหลดไฟล์ unitypackage ของ Input SDK พร้อมทรัพยากร Dependency ทั้งหมด คุณจะติดตั้ง .unitypackage ได้โดยเลือก ชิ้นงาน > นำเข้าแพ็กเกจ > แพ็กเกจที่กำหนดเอง และค้นหาไฟล์ที่คุณดาวน์โหลด

ติดตั้งโดยใช้ UPM

หรือคุณอาจติดตั้งแพ็กเกจโดยใช้ เครื่องมือจัดการแพ็กเกจของ Unity โดย ดาวน์โหลด .tgz และติดตั้งทรัพยากร Dependency ต่อไปนี้

ติดตั้งโดยใช้ OpenUPM

คุณสามารถติดตั้งแพ็กเกจโดยใช้ OpenUPM

$ openupm add com.google.android.libraries.play.games.inputmapping

เกมตัวอย่าง

ดูตัวอย่างวิธีผสานรวมกับ SDK อินพุตได้ที่ อุโมงค์ AGDK สำหรับเกม 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 ทั้งหมดของคุณ แต่อินพุต SDK คือ มีความฉลาดพอที่จะปิดการรีแมปหากคุณไม่สนับสนุนการรีแมป InputMap

ตัวอย่างนี้แมปคีย์ Space กับการทำงานของไดรฟ์

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
);

InputAction แบบคีย์เดียวที่แสดงในการวางซ้อน

การทำงานสามารถแสดงการป้อนข้อมูลด้วยเมาส์ได้เช่นกัน ตัวอย่างนี้ตั้งค่าคลิกซ้ายเป็น การดำเนินการย้าย

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
);

Mouse InputAction ที่แสดงในการวางซ้อน

จะมีการระบุชุดคีย์ด้วยการส่งรหัสคีย์หลายรหัสไปยัง InputAction ในตัวอย่างนี้ space + shift แมปกับ การดำเนินการ Turbo ซึ่งจะทำงานแม้ว่า Space จะแมปกับไดรฟ์ก็ตาม

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
);

InputAction แบบหลายคีย์ที่แสดงในการวางซ้อน

อินพุต SDK ทำให้คุณสามารถผสม ปุ่มเมาส์และปุ่มหลักเข้าด้วยกัน การกระทำเดียว ตัวอย่างนี้ระบุว่า Shift และคลิกขวา การกดร่วมกันจะเพิ่มจุดอ้างอิงในเกมตัวอย่างนี้:

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 ของเมาส์ที่แสดงในการวางซ้อน

InputAction มีฟิลด์ต่อไปนี้

  • ActionLabel: สตริงที่แสดงใน UI เพื่อแสดงการดำเนินการนี้ การแปลจะไม่สามารถทำได้โดยอัตโนมัติ ดังนั้นให้ปรับ ด้านหน้า
  • InputControls: กำหนดการควบคุมอินพุตที่การดำเนินการนี้ใช้ ควบคุมแผนที่กับรูปอักขระที่สอดคล้องกันในการวางซ้อน
  • InputActionId: ออบเจ็กต์ InputIdentifier รายการที่จัดเก็บรหัสหมายเลขและเวอร์ชัน ของ InputAction (ดูรหัสคีย์การติดตามสำหรับข้อมูลเพิ่มเติม ข้อมูล)
  • InputRemappingOption: หนึ่งใน InputEnums.REMAP_OPTION_ENABLED หรือ InputEnums.REMAP_OPTION_DISABLED ระบุว่ามีการเปิดใช้งานการดำเนินการหรือไม่ รีแมป หากเกมไม่รองรับการรีแมป คุณสามารถข้ามช่องนี้หรือ ก็แค่ตั้งค่าปิดใช้งาน
  • RemappedInputControls: ออบเจ็กต์ InputControls แบบอ่านอย่างเดียวที่ใช้อ่าน คีย์ที่รีแมปที่ผู้ใช้กำหนดไว้ในเหตุการณ์การรีแมป (ใช้สำหรับ การได้รับการแจ้งเตือนเมื่อเกิดเหตุการณ์รีแมป)

InputControls แสดงอินพุตที่เชื่อมโยงกับการดำเนินการและมีเมธอด ฟิลด์ต่อไปนี้:

  • AndroidKeycodes: เป็นรายการจำนวนเต็มที่แสดงการป้อนข้อมูลด้วยแป้นพิมพ์ ที่เชื่อมโยงกับการทำงาน ซึ่งมีการกำหนดไว้ในส่วน เหตุการณ์สําคัญ หรือคลาส AndroidKeycode สำหรับ Unity
  • MouseActions: เป็นรายการค่า MouseAction ที่แสดงอินพุตจากเมาส์ ที่เชื่อมโยงกับการดำเนินการนี้

กำหนดกลุ่มอินพุต

จัดกลุ่ม InputActions ด้วยการดำเนินการที่เกี่ยวข้องกันอย่างสมเหตุสมผลโดยใช้ InputGroups เพื่อ ปรับปรุงการนำทางและควบคุมการค้นพบได้ในการวางซ้อน ชิ้น รหัส InputGroup ต้องไม่ซ้ำกันสำหรับ InputGroups ทั้งหมดในเกมของคุณ

การจัดระเบียบการป้อนข้อมูลให้เป็นกลุ่มจะช่วยให้ผู้เล่นทำสิ่งต่างๆ ได้ง่ายขึ้น ค้นหาการเชื่อมโยงคีย์ที่ถูกต้องสำหรับบริบทปัจจุบัน

หากคุณรองรับการรีแมป คุณสามารถกำหนดว่า InputGroups สามารถทำอะไรได้บ้าง รีแมปแล้ว หากเกมของคุณไม่รองรับการรีแมป คุณควรตั้งค่าการรีแมป ตัวเลือกถูกปิดใช้งานสำหรับ InputGroups ทั้งหมดของคุณ แต่อินพุต 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
);

ตัวอย่างต่อไปนี้แสดงการควบคุมถนนและการควบคุมเมนู กลุ่มอินพุตในการวางซ้อน:

ภาพซ้อนทับที่แสดง InputMap ที่มีตัวควบคุมถนนและ
เมนูจะควบคุมกลุ่มอินพุต

InputGroup มีช่องต่อไปนี้

  • GroupLabel: สตริงที่จะแสดงในโฆษณาซ้อนทับที่ใช้เพื่อ จัดกลุ่มชุดของการดำเนินการอย่างมีตรรกะ ระบบจะไม่รวมสตริงนี้โดยอัตโนมัติ แปลแล้ว
  • InputActions: รายการ InputAction ออบเจ็กต์ที่คุณกำหนดก่อนหน้านี้ ครั้งแรก การดำเนินการเหล่านี้ทั้งหมดจะแสดงอยู่ใต้ส่วนหัวของกลุ่ม
  • InputGroupId: ออบเจ็กต์ InputIdentifier ที่จัดเก็บรหัสหมายเลขและ ของ InputGroup ดูรหัสคีย์การติดตามสำหรับ ข้อมูลเพิ่มเติม
  • InputRemappingOption: หนึ่งใน InputEnums.REMAP_OPTION_ENABLED หรือ InputEnums.REMAP_OPTION_DISABLED หากปิดใช้ ระบบจะ InputAction ทั้งหมด ออบเจ็กต์ที่อยู่ในกลุ่มนี้จะถูกปิดใช้การรีแมป ระบุว่ามีการเปิดใช้ตัวเลือกการแมปใหม่ หากเปิดใช้ การดำเนินการทั้งหมดที่เป็นของ ไปยังกลุ่มนี้ซ้ำได้ ยกเว้นกรณีที่บุคคลปิดใช้งานระบุไว้ การดำเนินการ

กำหนดบริบทสำหรับอินพุต

InputContexts อนุญาตให้เกมใช้ชุดการควบคุมแป้นพิมพ์ที่ต่างออกไปสำหรับ ในฉากต่างๆ ในเกม เช่น

  • คุณอาจระบุชุดอินพุตที่ต่างกันสำหรับการไปยังเมนูและการย้าย ในเกม
  • คุณสามารถระบุชุดอินพุตต่างๆ ได้ โดยขึ้นอยู่กับโหมดการเคลื่อนไหว ในเกม เช่น การขับรถเทียบกับการเดิน
  • คุณสามารถระบุชุดอินพุตต่างๆ ตามสถานะปัจจุบันของข้อมูล เช่น เดินทางข้ามโลกหรือเล่นเกมแต่ละด่าน

เมื่อใช้ InputContexts โฆษณาซ้อนทับจะแสดงกลุ่มของบริบทก่อน ที่ใช้งานอยู่ หากต้องการเปิดใช้ลักษณะการทำงานนี้ ให้เรียก setInputContext() เพื่อตั้งค่า เมื่อใดก็ตามที่เกมของคุณเข้าสู่ฉากอื่นๆ รูปภาพต่อไปนี้ แสดงให้เห็นพฤติกรรมนี้: ขณะขับรถ การควบคุมถนน จะแสดงด้านบนของการวางซ้อน เมื่อเปิด "ร้านค้า" "การควบคุมเมนู" จะแสดงด้านบนของการวางซ้อน

InputContexts ที่จัดเรียงกลุ่มในการวางซ้อน

การอัปเดตการวางซ้อนเหล่านี้สามารถทำได้โดยการตั้งค่า InputContext ที่แตกต่างกันที่ แต้มต่างๆ ในเกมของคุณ หากต้องการทำสิ่งต่อไปนี้

  1. จัดกลุ่ม InputActions ด้วยการดำเนินการที่เกี่ยวข้องเชิงตรรกะโดยใช้ InputGroups
  2. กำหนด 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 ระบุว่าความไวของเมาส์ และเมาส์ก็กลับอยู่บนแกน Y
  • InputMapId: ออบเจ็กต์ 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 เวอร์ชัน

รับการแจ้งเตือนเกี่ยวกับการรีแมปกิจกรรม (ไม่บังคับ)

รับการแจ้งเตือนเมื่อเกิดเหตุการณ์ที่รีแมปเพื่อรับทราบข้อมูลเกี่ยวกับคีย์ที่ใช้ใน เกมของคุณ การดำเนินการนี้จะช่วยให้เกมของคุณอัปเดตเนื้อหาที่แสดงบนหน้าจอเกมได้ ซึ่งใช้เพื่อแสดงส่วนควบคุมการดำเนินการ

รูปภาพต่อไปนี้แสดงตัวอย่างของลักษณะการทำงานนี้ ซึ่งหลังจากรีแมป แป้น G, P และ S ถึง J, X และ T ตามลำดับ องค์ประกอบ UI ของเกมจะอัปเดตเป็น แสดงคีย์ที่ผู้ใช้กำหนด

UI รีแอ็กต่อเหตุการณ์รีแมปโดยใช้ Callback InputRemappingListener

ฟังก์ชันนี้จะทำได้โดยการลงทะเบียน 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 อินสแตนซ์เมื่อปิดเกมของคุณ แม้ว่า 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 จะตรวจสอบความถูกต้องของแผนที่ที่คุณป้อน เทียบกับข้อผิดพลาดที่พบบ่อย สำหรับสถานการณ์ เช่น รหัสที่ไม่ซ้ำที่ซ้ำกัน การใช้ การแมปอินพุตหรือล้มเหลวในกฎการรีแมป (หากเปิดใช้การแมปใหม่) การวางซ้อนแสดงข้อความแสดงข้อผิดพลาดดังที่ระบุด้านล่าง การวางซ้อน SDK อินพุต

ยืนยันการติดตั้งใช้งาน 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 เพื่อให้แน่ใจว่า 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