Controller für verschiedene Android-Versionen unterstützen

Falls du Controller in deinem Spiel unterstützt, bist du dafür verantwortlich. um dafür zu sorgen, dass dein Spiel auf verschiedenen Geräten konsistent auf Controller reagiert die auf verschiedenen Android-Versionen laufen. So kannst du mit deinem Spiel und Ihre Spieler profitieren von einem nahtlosen Spielerlebnis mit auch dann, wenn sie ihr Android-Gerät wechseln oder upgraden.

In dieser Lektion wird gezeigt, wie die ab Android 4.1 verfügbaren APIs verwendet werden. abwärtskompatibel sein, sodass Ihr Spiel Folgendes unterstützt: Funktionen auf Geräten mit Android 3.1 und höher:

  • Das Spiel kann erkennen, ob ein neuer Controller hinzugefügt, geändert oder entfernt wird.
  • Das Spiel kann die Funktionen eines Controllers abfragen.
  • Das Spiel kann eingehende Bewegungsereignisse von einem Controller erkennen.

Die Beispiele in dieser Lektion basieren auf der Referenzimplementierung aus der Beispiel-ControllerSample.zip zum Download zur Verfügung gestellt oben. In diesem Beispiel wird gezeigt, wie InputManagerCompat implementiert wird. um verschiedene Android-Versionen zu unterstützen. Um das Beispiel zu kompilieren, muss Android 4.1 (API-Level 16) oder höher verwenden. Nach der Kompilierung kann die Beispiel-App läuft auf jedem Gerät mit Android 3.1 (API-Level 12) oder höher, Ziel.

Auf abstrakte APIs für die Unterstützung von Gamecontrollern vorbereiten

Angenommen, Sie möchten ermitteln, Der Status hat sich auf Geräten mit Android 3.1 (API-Level 12) geändert. Sie können jedoch die APIs nur ab Android 4.1 (API-Level 16) verfügbar sind. müssen Sie eine Implementierung bereitstellen, die Android 4.1 und höher unterstützt, während Bereitstellung eines Fallback-Mechanismus, der Android 3.1 bis Android 4.0 unterstützt.

Um zu ermitteln, für welche Funktionen ein solcher Fallback-Mechanismus erforderlich ist, Bei älteren Versionen finden Sie in Tabelle 1 die Unterschiede bei der Unterstützung von Gamecontrollern. zwischen Android 3.1 (API-Level 12) und 4.1 (API-Level) 16).

Tabelle 1 APIs für Gamecontroller-Unterstützung in Android-Versionen vergleichen.

Daten zum Verantwortlichen Controller-API API-Level 12 API-Level 16
Geräteidentifikation getInputDeviceIds()  
getInputDevice()  
getVibrator()  
SOURCE_JOYSTICK
SOURCE_GAMEPAD
Verbindungsstatus onInputDeviceAdded()  
onInputDeviceChanged()  
onInputDeviceRemoved()  
Identifizierung des Eingabeereignisses Drücken des Steuerkreuzes ( KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT, KEYCODE_DPAD_RIGHT, KEYCODE_DPAD_CENTER)
Drücken der Gamepad-Taste ( BUTTON_A, BUTTON_B, BUTTON_THUMBL, BUTTON_THUMBR, BUTTON_SELECT, BUTTON_START, BUTTON_R1, BUTTON_L1, BUTTON_R2, BUTTON_L2
Bewegung des Joysticks und des Huts ( AXIS_X, AXIS_Y, AXIS_Z, AXIS_RZ, AXIS_HAT_X, AXIS_HAT_Y)
Drücken des analogen Triggers ( AXIS_LTRIGGER, AXIS_RTRIGGER)

Mit Abstraktion können Sie versionsbasierte Controller-Unterstützung erstellen, plattformübergreifend funktioniert. Dieser Ansatz umfasst die folgenden Schritte:

  1. Definieren Sie eine zwischengeschaltete Java-Schnittstelle, die die Implementierung eines die für Ihr Spiel erforderlichen Controller-Funktionen
  2. Proxy-Implementierung Ihrer Schnittstelle erstellen, die APIs in Android verwendet 4.1 und höher.
  3. Erstellen Sie eine benutzerdefinierte Implementierung Ihrer Schnittstelle, die verfügbare APIs verwendet. Android 3.1 bis Android 4.0.
  4. Erstellen Sie die Logik für den Wechsel zwischen diesen Implementierungen zur Laufzeit. und beginnen mit der Nutzung der Benutzeroberfläche in Ihrem Spiel.

Einen Überblick darüber, wie mithilfe der Abstraktion sichergestellt werden kann, dass Anwendungen abwärtskompatibel mit verschiedenen Android-Versionen funktionieren, siehe Wird erstellt... Abwärtskompatible Benutzeroberflächen.

Schnittstelle für Abwärtskompatibilität hinzufügen

Um Abwärtskompatibilität zu gewährleisten, können Sie eine benutzerdefinierte Schnittstelle erstellen und dann versionspezifische Implementierungen hinzufügen. Ein Vorteil dieses Ansatzes ist, können Sie die öffentlichen Schnittstellen unter Android 4.1 (API-Level 16) spiegeln, Gamecontroller unterstützen.

Kotlin

// The InputManagerCompat interface is a reference example.
// The full code is provided in the ControllerSample.zip sample.
interface InputManagerCompat {
    val inputDeviceIds: IntArray
    fun getInputDevice(id: Int): InputDevice

    fun registerInputDeviceListener(
            listener: InputManager.InputDeviceListener,
            handler: Handler?
    )

    fun unregisterInputDeviceListener(listener:InputManager.InputDeviceListener)

    fun onGenericMotionEvent(event: MotionEvent)

    fun onPause()
    fun onResume()

    interface InputDeviceListener {
        fun onInputDeviceAdded(deviceId: Int)
        fun onInputDeviceChanged(deviceId: Int)
        fun onInputDeviceRemoved(deviceId: Int)
    }
}

Java

// The InputManagerCompat interface is a reference example.
// The full code is provided in the ControllerSample.zip sample.
public interface InputManagerCompat {
    ...
    public InputDevice getInputDevice(int id);
    public int[] getInputDeviceIds();

    public void registerInputDeviceListener(
            InputManagerCompat.InputDeviceListener listener,
            Handler handler);
    public void unregisterInputDeviceListener(
            InputManagerCompat.InputDeviceListener listener);

    public void onGenericMotionEvent(MotionEvent event);

    public void onPause();
    public void onResume();

    public interface InputDeviceListener {
        void onInputDeviceAdded(int deviceId);
        void onInputDeviceChanged(int deviceId);
        void onInputDeviceRemoved(int deviceId);
    }
    ...
}

Die Schnittstelle InputManagerCompat bietet die folgenden Methoden:

getInputDevice()
Spiegeln getInputDevice(). Erhält InputDevice Objekt, das die Funktionen eines Controllers darstellt.
getInputDeviceIds()
Spiegeln getInputDeviceIds(). Gibt ein Array von Ganzzahlen zurück, die jeweils also eine ID für ein anderes Eingabegerät. Dies ist nützlich, wenn Sie ein Spiel, das mehrere Spieler unterstützt, und Sie wissen möchten, wie viele Spieler Controller verbunden.
registerInputDeviceListener()
Spiegeln registerInputDeviceListener(). Sie können sich registrieren, um informiert zu werden, wenn ein neues Gerät hinzugefügt, geändert oder entfernt wird.
unregisterInputDeviceListener()
Spiegelt unregisterInputDeviceListener(). Hebt die Registrierung eines Eingabegeräte-Listeners auf.
onGenericMotionEvent()
Spiegelt onGenericMotionEvent(). Ermöglicht es deinem Spiel, abzufangen und zu verarbeiten MotionEvent-Objekte und Achsenwerte, die Ereignisse darstellen wie Joystickbewegungen und analoges Betätigen des Triggers.
onPause()
Beendet die Abfrage von Controller-Ereignissen, wenn die Hauptaktivität pausiert wird oder wenn das Spiel den Fokus nicht mehr hat.
onResume()
Startet die Abfrage von Controller-Ereignissen, wenn das Ereignis wird fortgesetzt oder wenn das Spiel beginnt und in der im Vordergrund.
InputDeviceListener
Spiegelt InputManager.InputDeviceListener . Informiert dein Spiel, wenn ein Controller hinzugefügt, geändert oder entfernt.

Erstellen Sie als Nächstes funktionstüchtige InputManagerCompat-Implementierungen auf verschiedenen Plattformversionen. Wenn in Ihrem Spiel Android 4.1 oder höher und ruft eine InputManagerCompat-Methode auf, die Proxy-Implementierung die entsprechende Methode in InputManager aufruft. Wenn Ihr Spiel jedoch unter Android 3.1 bis Android 4.0 läuft, ist die benutzerdefinierte Implementierung verarbeitet Aufrufe an InputManagerCompat-Methoden mithilfe von APIs, die nicht später als Android 3.1 eingeführt wurden. Unabhängig davon, wird zur Laufzeit eine versionsspezifische Implementierung verwendet, die Implementierung besteht die Rückrufergebnisse transparent an das Spiel zurückgegeben werden.

Abbildung 1: Klassendiagramm der schnittstellen- und versionsspezifischen Implementierungen.

Schnittstelle unter Android 4.1 und höher implementieren

InputManagerCompatV16 ist eine Implementierung des InputManagerCompat-Schnittstelle, die Methodenaufrufe an eine tatsächliche InputManager und InputManager.InputDeviceListener. Die InputManager wird vom System abgerufen Context.

Kotlin

// The InputManagerCompatV16 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV16(
        context: Context,
        private val inputManager: InputManager =
            context.getSystemService(Context.INPUT_SERVICE) as InputManager,
        private val listeners:
            MutableMap<InputManager.InputDeviceListener, V16InputDeviceListener> = mutableMapOf()
) : InputManagerCompat {
    override val inputDeviceIds: IntArray = inputManager.inputDeviceIds

    override fun getInputDevice(id: Int): InputDevice = inputManager.getInputDevice(id)

    override fun registerInputDeviceListener(
            listener: InputManager.InputDeviceListener,
            handler: Handler?
    ) {
        V16InputDeviceListener(listener).also { v16listener ->
            inputManager.registerInputDeviceListener(v16listener, handler)
            listeners += listener to v16listener
        }
    }

    // Do the same for unregistering an input device listener
    ...

    override fun onGenericMotionEvent(event: MotionEvent) {
        // unused in V16
    }

    override fun onPause() {
        // unused in V16
    }

    override fun onResume() {
        // unused in V16
    }

}

class V16InputDeviceListener(
        private val idl: InputManager.InputDeviceListener
) : InputManager.InputDeviceListener {

    override fun onInputDeviceAdded(deviceId: Int) {
        idl.onInputDeviceAdded(deviceId)
    }
    // Do the same for device change and removal
    ...
}

Java

// The InputManagerCompatV16 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV16 implements InputManagerCompat {

    private final InputManager inputManager;
    private final Map<InputManagerCompat.InputDeviceListener,
            V16InputDeviceListener> listeners;

    public InputManagerV16(Context context) {
        inputManager = (InputManager)
                context.getSystemService(Context.INPUT_SERVICE);
        listeners = new HashMap<InputManagerCompat.InputDeviceListener,
                V16InputDeviceListener>();
    }

    @Override
    public InputDevice getInputDevice(int id) {
        return inputManager.getInputDevice(id);
    }

    @Override
    public int[] getInputDeviceIds() {
        return inputManager.getInputDeviceIds();
    }

    static class V16InputDeviceListener implements
            InputManager.InputDeviceListener {
        final InputManagerCompat.InputDeviceListener mIDL;

        public V16InputDeviceListener(InputDeviceListener idl) {
            mIDL = idl;
        }

        @Override
        public void onInputDeviceAdded(int deviceId) {
            mIDL.onInputDeviceAdded(deviceId);
        }

        // Do the same for device change and removal
        ...
    }

    @Override
    public void registerInputDeviceListener(InputDeviceListener listener,
            Handler handler) {
        V16InputDeviceListener v16Listener = new
                V16InputDeviceListener(listener);
        inputManager.registerInputDeviceListener(v16Listener, handler);
        listeners.put(listener, v16Listener);
    }

    // Do the same for unregistering an input device listener
    ...

    @Override
    public void onGenericMotionEvent(MotionEvent event) {
        // unused in V16
    }

    @Override
    public void onPause() {
        // unused in V16
    }

    @Override
    public void onResume() {
        // unused in V16
    }

}

Benutzeroberfläche in Android 3.1 bis Android 4.0 implementieren

Um eine Implementierung von InputManagerCompat zu erstellen, die Android 3.1 bis Android 4.0 unterstützt, können Sie folgende Objekte:

  • Ein SparseArray mit Geräte-IDs zum Verfolgen des Controller, die mit dem Gerät verbunden sind.
  • Ein Handler zum Verarbeiten von Geräteereignissen. Beim Starten einer App oder fortgesetzt wird, erhält das Handler eine Nachricht zum Starten des Abfragens. um den Controller zu trennen. Handler startet einen Schleife, um jeden bekannten verbundenen Controller zu prüfen und zu sehen, ob eine Geräte-ID zurückgegeben. Ein null-Rückgabewert gibt an, dass der Controller nicht verbunden. Handler beendet die Abfrage, wenn die Anwendung pausiert.
  • Ein Map von InputManagerCompat.InputDeviceListener Objekte. Mit den Listenern aktualisieren Sie den Verbindungsstatus der erfassten Gamecontroller.

Kotlin

// The InputManagerCompatV9 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
class InputManagerV9(
        val devices: SparseArray<Array<Long>> = SparseArray(),
        private val listeners:
        MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf()
) : InputManagerCompat {
    private val defaultHandler: Handler = PollingMessageHandler(this)
    
}

Java

// The InputManagerCompatV9 class is a reference implementation.
// The full code is provided in the ControllerSample.zip sample.
public class InputManagerV9 implements InputManagerCompat {
    private final SparseArray<long[]> devices;
    private final Map<InputDeviceListener, Handler> listeners;
    private final Handler defaultHandler;
    

    public InputManagerV9() {
        devices = new SparseArray<long[]>();
        listeners = new HashMap<InputDeviceListener, Handler>();
        defaultHandler = new PollingMessageHandler(this);
    }
}

Implementieren Sie ein PollingMessageHandler-Objekt, das die Handler und überschreiben den handleMessage() . Diese Methode prüft, ob ein angeschlossener Controller und benachrichtigt registrierte Listener.

Kotlin

private class PollingMessageHandler(
        inputManager: InputManagerV9,
        private val mInputManager: WeakReference<InputManagerV9> = WeakReference(inputManager)
) : Handler() {

    override fun handleMessage(msg: Message) {
        super.handleMessage(msg)
        when (msg.what) {
            MESSAGE_TEST_FOR_DISCONNECT -> {
                mInputManager.get()?.also { imv ->
                    val time = SystemClock.elapsedRealtime()
                    val size = imv.devices.size()
                    for (i in 0 until size) {
                        imv.devices.valueAt(i)?.also { lastContact ->
                            if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
                                // check to see if the device has been
                                // disconnected
                                val id = imv.devices.keyAt(i)
                                if (null == InputDevice.getDevice(id)) {
                                    // Notify the registered listeners
                                    // that the game controller is disconnected
                                    imv.devices.remove(id)
                                } else {
                                    lastContact[0] = time
                                }
                            }
                        }
                    }
                    sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME)
                }
            }
        }
    }
}

Java

private static class PollingMessageHandler extends Handler {
    private final WeakReference<InputManagerV9> inputManager;

    PollingMessageHandler(InputManagerV9 im) {
        inputManager = new WeakReference<InputManagerV9>(im);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case MESSAGE_TEST_FOR_DISCONNECT:
                InputManagerV9 imv = inputManager.get();
                if (null != imv) {
                    long time = SystemClock.elapsedRealtime();
                    int size = imv.devices.size();
                    for (int i = 0; i < size; i++) {
                        long[] lastContact = imv.devices.valueAt(i);
                        if (null != lastContact) {
                            if (time - lastContact[0] > CHECK_ELAPSED_TIME) {
                                // check to see if the device has been
                                // disconnected
                                int id = imv.devices.keyAt(i);
                                if (null == InputDevice.getDevice(id)) {
                                    // Notify the registered listeners
                                    // that the game controller is disconnected
                                    imv.devices.remove(id);
                                } else {
                                    lastContact[0] = time;
                                }
                            }
                        }
                    }
                    sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
                            CHECK_ELAPSED_TIME);
                }
                break;
        }
    }
}

Um das Abfragen zum Trennen der Verbindung zum Controller zu starten und zu stoppen, überschreiben Sie diesen Methoden:

Kotlin

private const val MESSAGE_TEST_FOR_DISCONNECT = 101
private const val CHECK_ELAPSED_TIME = 3000L

class InputManagerV9(
        val devices: SparseArray<Array<Long>> = SparseArray(),
        private val listeners:
        MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf()
) : InputManagerCompat {
    ...
    override fun onPause() {
        defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT)
    }

    override fun onResume() {
        defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT, CHECK_ELAPSED_TIME)
    }
    ...
}

Java

private static final int MESSAGE_TEST_FOR_DISCONNECT = 101;
private static final long CHECK_ELAPSED_TIME = 3000L;

@Override
public void onPause() {
    defaultHandler.removeMessages(MESSAGE_TEST_FOR_DISCONNECT);
}

@Override
public void onResume() {
    defaultHandler.sendEmptyMessageDelayed(MESSAGE_TEST_FOR_DISCONNECT,
            CHECK_ELAPSED_TIME);
}

Um zu erkennen, dass ein Eingabegerät hinzugefügt wurde, überschreiben Sie die onGenericMotionEvent()-Methode. Wenn das System ein Bewegungsereignis meldet, Prüfen Sie, ob dieses Ereignis von einer Geräte-ID stammt, die bereits erfasst wird, oder von einem neue Geräte-ID. Wenn die Geräte-ID neu ist, benachrichtigen Sie die registrierten Hörer.

Kotlin

override fun onGenericMotionEvent(event: MotionEvent) {
    // detect new devices
    val id = event.deviceId
    val timeArray: Array<Long> = mDevices.get(id) ?: run {
        // Notify the registered listeners that a game controller is added
        ...
        arrayOf<Long>().also {
            mDevices.put(id, it)
        }
    }
    timeArray[0] = SystemClock.elapsedRealtime()
}

Java

@Override
public void onGenericMotionEvent(MotionEvent event) {
    // detect new devices
    int id = event.getDeviceId();
    long[] timeArray = mDevices.get(id);
    if (null == timeArray) {
        // Notify the registered listeners that a game controller is added
        ...
        timeArray = new long[1];
        mDevices.put(id, timeArray);
    }
    long time = SystemClock.elapsedRealtime();
    timeArray[0] = time;
}

Die Benachrichtigung über Listener wird mithilfe der Methode Handler-Objekt zum Senden einer DeviceEvent Runnable-Objekt für die Nachrichtenwarteschlange. Das DeviceEvent enthält einen Verweis auf ein InputManagerCompat.InputDeviceListener. Wann? wird DeviceEvent ausgeführt, die entsprechende Callback-Methode des Listeners. wird aufgerufen, um zu signalisieren, ob der Controller hinzugefügt, geändert oder entfernt wurde.

Kotlin

class InputManagerV9(
        val devices: SparseArray<Array<Long>> = SparseArray(),
        private val listeners:
        MutableMap<InputManager.InputDeviceListener, Handler> = mutableMapOf()
) : InputManagerCompat {
    ...
    override fun registerInputDeviceListener(
            listener: InputManager.InputDeviceListener,
            handler: Handler?
    ) {
        listeners[listener] = handler ?: defaultHandler
    }

    override fun unregisterInputDeviceListener(listener: InputManager.InputDeviceListener) {
        listeners.remove(listener)
    }

    private fun notifyListeners(why: Int, deviceId: Int) {
        // the state of some device has changed
        listeners.forEach { listener, handler ->
            DeviceEvent.getDeviceEvent(why, deviceId, listener).also {
                handler?.post(it)
            }
        }
    }
    ...
}

private val sObjectQueue: Queue<DeviceEvent> = ArrayDeque<DeviceEvent>()

private class DeviceEvent(
        private var mMessageType: Int,
        private var mId: Int,
        private var mListener: InputManager.InputDeviceListener
) : Runnable {

    companion object {
        fun getDeviceEvent(messageType: Int, id: Int, listener: InputManager.InputDeviceListener) =
                sObjectQueue.poll()?.apply {
                    mMessageType = messageType
                    mId = id
                    mListener = listener
                } ?: DeviceEvent(messageType, id, listener)

    }

    override fun run() {
        when(mMessageType) {
            ON_DEVICE_ADDED -> mListener.onInputDeviceAdded(mId)
            ON_DEVICE_CHANGED -> mListener.onInputDeviceChanged(mId)
            ON_DEVICE_REMOVED -> mListener.onInputDeviceChanged(mId)
            else -> {
                // Handle unknown message type
            }
        }
    }

}

Java

@Override
public void registerInputDeviceListener(InputDeviceListener listener,
        Handler handler) {
    listeners.remove(listener);
    if (handler == null) {
        handler = defaultHandler;
    }
    listeners.put(listener, handler);
}

@Override
public void unregisterInputDeviceListener(InputDeviceListener listener) {
    listeners.remove(listener);
}

private void notifyListeners(int why, int deviceId) {
    // the state of some device has changed
    if (!listeners.isEmpty()) {
        for (InputDeviceListener listener : listeners.keySet()) {
            Handler handler = listeners.get(listener);
            DeviceEvent odc = DeviceEvent.getDeviceEvent(why, deviceId,
                    listener);
            handler.post(odc);
        }
    }
}

private static class DeviceEvent implements Runnable {
    private int mMessageType;
    private int mId;
    private InputDeviceListener mListener;
    private static Queue<DeviceEvent> sObjectQueue =
            new ArrayDeque<DeviceEvent>();
    ...

    static DeviceEvent getDeviceEvent(int messageType, int id,
            InputDeviceListener listener) {
        DeviceEvent curChanged = sObjectQueue.poll();
        if (null == curChanged) {
            curChanged = new DeviceEvent();
        }
        curChanged.mMessageType = messageType;
        curChanged.mId = id;
        curChanged.mListener = listener;
        return curChanged;
    }

    @Override
    public void run() {
        switch (mMessageType) {
            case ON_DEVICE_ADDED:
                mListener.onInputDeviceAdded(mId);
                break;
            case ON_DEVICE_CHANGED:
                mListener.onInputDeviceChanged(mId);
                break;
            case ON_DEVICE_REMOVED:
                mListener.onInputDeviceRemoved(mId);
                break;
            default:
                // Handle unknown message type
                ...
                break;
        }
        // Put this runnable back in the queue
        sObjectQueue.offer(this);
    }
}

Sie haben jetzt zwei Implementierungen von InputManagerCompat: eine, die funktioniert auf Geräten mit Android 4.1 und höher. für Geräte mit Android 3.1 bis Android 4.0.

Versionsspezifische Implementierung verwenden

Die versionsspezifische Wechsellogik ist in einer Klasse implementiert, die als Factory

Kotlin

object Factory {
    fun getInputManager(context: Context): InputManagerCompat =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                InputManagerV16(context)
            } else {
                InputManagerV9()
            }
}

Java

public static class Factory {
    public static InputManagerCompat getInputManager(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            return new InputManagerV16(context);
        } else {
            return new InputManagerV9();
        }
    }
}

Jetzt können Sie einfach ein InputManagerCompat-Objekt instanziieren InputManagerCompat.InputDeviceListener in deinem Haupt- View Aufgrund der von Ihnen festgelegten Logik für den Versionswechsel verwendet Ihr Spiel automatisch die Implementierung, Android-Version auf dem Gerät.

Kotlin

class GameView(context: Context) : View(context), InputManager.InputDeviceListener {
    private val inputManager: InputManagerCompat = Factory.getInputManager(context).apply {
        registerInputDeviceListener(this@GameView, null)
        ...
    }
    ...
}

Java

public class GameView extends View implements InputDeviceListener {
    private InputManagerCompat inputManager;
    ...

    public GameView(Context context, AttributeSet attrs) {
        inputManager =
                InputManagerCompat.Factory.getInputManager(this.getContext());
        inputManager.registerInputDeviceListener(this, null);
        ...
    }
}

Als Nächstes überschreiben Sie onGenericMotionEvent()-Methode in Ihrer Hauptansicht, wie unter MotionEvent aus einem Spiel verarbeiten Controller Controller-Ereignisse sollten jetzt in deinem Spiel verarbeitet werden können regelmäßig auf Geräten mit Android 3.1 (API-Level 12) und höher.

Kotlin

override fun onGenericMotionEvent(event: MotionEvent): Boolean {
    inputManager.onGenericMotionEvent(event)

    // Handle analog input from the controller as normal
    ...
    return super.onGenericMotionEvent(event)
}

Java

@Override
public boolean onGenericMotionEvent(MotionEvent event) {
    inputManager.onGenericMotionEvent(event);

    // Handle analog input from the controller as normal
    ...
    return super.onGenericMotionEvent(event);
}

Eine vollständige Implementierung dieses Kompatibilitätscodes finden Sie in der Klasse GameView im Beispiel-ControllerSample.zip oben zum Download verfügbar.