Na poziomie systemu Android zgłasza kody zdarzeń wejściowych z kontrolerów gier jako kody klawiszy i wartości osi Androida. Kody i wartości w grze możesz przekształcić w określone działania.
Gdy gracze podłączą kontroler do swoich urządzeń z Androidem fizycznie lub bezprzewodowo, system automatycznie wykryje kontroler jako urządzenie wejściowe i zacznie zgłaszać zdarzenia związane z wejściami. Gra może odbierać te zdarzenia wprowadzania, wdrażając w aktywnej Activity
lub skoncentrowanej View
te metody wywołania (powinnaś zaimplementować wywołania Activity
lub View
, ale nie obydwa):
- Od:
Activity
:dispatchGenericMotionEvent(android.view. MotionEvent)
Wywoływany do przetwarzania ogólnych zdarzeń związanych z ruchu, takich jak ruchy drążkiem.
dispatchKeyEvent(android.view.KeyEvent)
Wywoływane w celu przetwarzania kluczowych zdarzeń, takich jak naciśnięcie lub zwolnienie przycisku na padzie do gier lub pada kierunkowego.
- Od:
View
:onGenericMotionEvent(android.view.MotionEvent)
Wywoływany do przetwarzania ogólnych zdarzeń związanych z ruchu, takich jak ruchy drążkiem.
onKeyDown(int, android.view.KeyEvent)
Wywoływany do przetwarzania naciśnięcia fizycznego przycisku, takiego jak przycisk pada lub przycisk D-pad.
onKeyUp(int, android.view.KeyEvent)
Wywoływany do przetworzenia zwolnienia fizycznego klawisza, takiego jak przycisk pada lub przycisk D-pad.
Zalecane podejście polega na rejestrowaniu zdarzeń z konkretnego obiektu View
, z którym użytkownik wchodzi w interakcję.
Aby uzyskać informacje o typie otrzymanego zdarzenia wejściowego, sprawdź te obiekty podane przez wywołania zwrotne:
KeyEvent
- Obiekt opisujący zdarzenia przycisków kierunkowych (D-pad) i przycisków kontrolera. Kluczowe zdarzenia są opatrzone kodem klucza, który wskazuje konkretny przycisk, np.
DPAD_DOWN
lubBUTTON_A
. Aby uzyskać kod klucza, wywołaj funkcjęgetKeyCode()
lub użyj wywołań zwrotnych kluczowych zdarzeń, takich jakonKeyDown()
. MotionEvent
- Obiekt opisujący dane wejściowe przekazywane za pomocą joysticka i ruchu spustu po bokach. Zdarzenia ruchu są opatrzone kodem działania i zestawem wartości osi. Kod działania określa stan, który wystąpił, np. ruch joysticka. Wartości na osiach opisują położenie i inne właściwości ruchu w przypadku konkretnego elementu sterującego fizycznego, np.
AXIS_X
lubAXIS_RTRIGGER
. Kod działania możesz uzyskać, wywołując funkcjęgetAction()
, a wartość osi – wywołując funkcjęgetAxisValue()
.
W tej lekcji skupiamy się na tym, jak obsługiwać dane wejściowe z najczęstszych typów elementów sterujących (przycisków pada, padów kierunkowych i joysticków) na ekranie gry. Aby to zrobić, należy zaimplementować wspomniane metody wywołania zwrotnego View
oraz przetworzyć obiekty KeyEvent
i MotionEvent
.
Sprawdź, czy kontroler gier jest podłączony
Podczas raportowania zdarzeń wejściowych Android nie rozróżnia zdarzeń z kontrolera innego niż kontroler do gier. Na przykład działanie na ekranie dotykowym generuje zdarzenie AXIS_X
, które reprezentuje współrzędną X powierzchni dotykowej, a joystick – zdarzenie AXIS_X
reprezentujące pozycję X joysticka. Jeśli Twoja gra obsługuje dane wejściowe z kontrolera, najpierw sprawdź, czy dane te pochodzą z odpowiedniego typu źródła.
Aby sprawdzić, czy połączone urządzenie wejściowe jest kontrolerem do gier, wywołaj funkcję getSources()
, aby uzyskać połączone pole bitowe typów źródeł danych obsługiwanych przez to urządzenie. Następnie możesz sprawdzić, czy te pola są prawidłowo skonfigurowane:
- Typ źródła
SOURCE_GAMEPAD
oznacza, że urządzenie wejściowe ma przyciski pada do gier (np.BUTTON_A
). Pamiętaj, że ten typ źródła nie wskazuje ściśle, czy kontroler ma przyciski pada kierunkowego, ale większość padów do gier ma elementy sterujące kierunkowe. - Typ źródła
SOURCE_DPAD
oznacza, że urządzenie wejściowe ma przyciski na padach kierunkowych (np.DPAD_UP
). - Typ źródła
SOURCE_JOYSTICK
wskazuje, że urządzenie wejściowe ma analogowe elementy sterujące (np. joystick, który rejestruje ruchy wzdłuż osiAXIS_X
iAXIS_Y
).
Poniższy fragment kodu pokazuje metodę pomocniczą, która umożliwia sprawdzenie, czy połączone urządzenia wejściowe są kontrolerami gier. Jeśli tak, metoda pobiera identyfikatory urządzeń kontrolerów gier. Następnie możesz powiązać identyfikator każdego urządzenia z graczem w grze i przetwarzać działania w grze osobno dla każdego połączonego gracza. Więcej informacji o obsługiwaniu wielu kontrolerów do gier połączonych jednocześnie na tym samym urządzeniu z Androidem znajdziesz w artykule Obsługa wielu kontrolerów do gier.
Kotlin
fun getGameControllerIds(): List<Int> { val gameControllerDeviceIds = mutableListOf<Int>() val deviceIds = InputDevice.getDeviceIds() deviceIds.forEach { deviceId -> InputDevice.getDevice(deviceId).apply { // Verify that the device has gamepad buttons, control sticks, or both. if (sources and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD || sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK) { // This device is a game controller. Store its device ID. gameControllerDeviceIds .takeIf { !it.contains(deviceId) } ?.add(deviceId) } } } return gameControllerDeviceIds }
Java
public ArrayList<Integer> getGameControllerIds() { ArrayList<Integer> gameControllerDeviceIds = new ArrayList<Integer>(); int[] deviceIds = InputDevice.getDeviceIds(); for (int deviceId : deviceIds) { InputDevice dev = InputDevice.getDevice(deviceId); int sources = dev.getSources(); // Verify that the device has gamepad buttons, control sticks, or both. if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { // This device is a game controller. Store its device ID. if (!gameControllerDeviceIds.contains(deviceId)) { gameControllerDeviceIds.add(deviceId); } } } return gameControllerDeviceIds; }
Możesz też sprawdzić, czy podłączony kontroler do gier obsługuje indywidualne funkcje wejściowe. Może to być przydatne, jeśli chcesz, aby gra używała tylko danych wejściowych z zestawu obsługiwanych przez nią elementów sterujących.
Aby wykryć, czy podłączony kontroler do gier obsługuje określony kod klawisza lub oś, użyj tych metod:
- W Androidzie 4.4 (poziom interfejsu API 19) lub nowszym możesz sprawdzić, czy kod klawisza jest obsługiwany przez podłączony kontroler do gier, wywołując funkcję
hasKeys(int...)
. - W Androidzie 3.1 (poziom interfejsu API 12) lub nowszym możesz znaleźć wszystkie dostępne osie obsługiwane przez podłączony kontroler do gier, wywołując najpierw funkcję
getMotionRanges()
. Następnie po każdym zwróconym obiekcieInputDevice.MotionRange
wywołaj poleceniegetAxis()
, aby uzyskać identyfikator jego osi.
Przetwarzanie naciśnięć przycisków kontrolera
Rysunek 1 przedstawia, jak Android mapuje kody klawiszy i wartości osi na fizyczne elementy sterujące w większości kontrolerów gier.
Objaśnienia na ilustracji odnoszą się do tych informacji:
Typowe kody klawiszy generowane przez naciśnięcia przycisków kontrolera to BUTTON_A
, BUTTON_B
, BUTTON_SELECT
i BUTTON_START
. Niektóre kontrolery uruchamiają kod klawisza DPAD_CENTER
, gdy naciśniesz środkową część krzyżaka. Gra może sprawdzać kod klucza, wywołując funkcję getKeyCode()
lub używając wywołań zwrotnych kluczowego zdarzenia, np. onKeyDown()
. Jeśli gra reprezentuje zdarzenie związane z Twoją grą, przetwórz ją jako działanie w grze. Tabela 1 zawiera zalecane działania w przypadku najpopularniejszych przycisków padów do gier.
Działanie w grze | Kod klawisza przycisku |
---|---|
Uruchomić grę w menu głównym lub wstrzymać/wznowić grę | BUTTON_START * |
Wyświetl menu | BUTTON_SELECT * i KEYCODE_MENU * |
To samo zachowanie, co w przypadku przycisku Wstecz na Androidzie, opisane w przewodniku po projektowaniu nawigacji. | KEYCODE_BACK |
Wróć do poprzedniego elementu w menu | BUTTON_B |
potwierdzić wybór lub wykonać główne działanie w grze; | BUTTON_A i DPAD_CENTER |
* Gra nie powinna wymagać obecności przycisków Start, Select ani Menu.
Wskazówka: rozważ dodanie w grze ekranu konfiguracji, aby użytkownicy mogli spersonalizować ich mapy kontrolera do działań w grze.
Ten fragment kodu pokazuje, jak możesz zastąpić funkcję onKeyDown()
, aby powiązać naciśnięcia przycisków BUTTON_A
i DPAD_CENTER
z działaniem w grze.
Kotlin
class GameView(...) : View(...) { ... override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { var handled = false if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) { if (event.repeatCount == 0) { when (keyCode) { // Handle gamepad and D-pad button presses to navigate the ship ... else -> { keyCode.takeIf { isFireKey(it) }?.run { // Update the ship object to fire lasers ... handled = true } } } } if (handled) { return true } } return super.onKeyDown(keyCode, event) } // Here we treat Button_A and DPAD_CENTER as the primary action // keys for the game. private fun isFireKey(keyCode: Int): Boolean = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_BUTTON_A }
Java
public class GameView extends View { ... @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { if (event.getRepeatCount() == 0) { switch (keyCode) { // Handle gamepad and D-pad button presses to // navigate the ship ... default: if (isFireKey(keyCode)) { // Update the ship object to fire lasers ... handled = true; } break; } } if (handled) { return true; } } return super.onKeyDown(keyCode, event); } private static boolean isFireKey(int keyCode) { // Here we treat Button_A and DPAD_CENTER as the primary action // keys for the game. return keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_BUTTON_A; } }
Uwaga: w Androidzie 4.2 (poziom interfejsu API 17) i starszych system domyślnie traktuje BUTTON_A
jako klawisz Androida Wstecz. Jeśli Twoja aplikacja obsługuje te wersje Androida, pamiętaj, aby traktować BUTTON_A
jako główne działanie gry. Aby określić bieżącą wersję pakietu Android SDK na urządzeniu, sprawdź wartość Build.VERSION.SDK_INT
.
Przetwarzanie danych z pada kierunkowego
4-kierunkowy panel kierunkowy (D-pad) to powszechny element sterujący w wielu kontrolerach do gier. Android zgłasza naciśnięcia przycisku w górę i w dół jako zdarzenia AXIS_HAT_Y
o zakresie od -1,0 (góra) do 1,0 (dół), a naciśnięcia przycisku w lewo lub w prawo jako zdarzenia AXIS_HAT_X
o zakresie od -1,0 (lewo) do 1,0 (prawo).
Niektóre kontrolery zamiast tego raportują naciśnięcia przycisków D-pad za pomocą kodu klawisza. Jeśli w Twojej grze chodzi o naciśnięcia pada kierunkowego, zdarzenia związane z osią kapelusza i kody klawiszy na padzie kierunkowym należy traktować jak te same zdarzenia wejściowe, co zaleca się w tabeli 2.
Działanie w grze | Kod klawisza pada kierunkowego | Hat Axis Code |
---|---|---|
W górę | KEYCODE_DPAD_UP |
AXIS_HAT_Y (wartości od 0 do –1,0) |
W dół | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (wartości od 0 do 1,0) |
Przenieś w lewo | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (wartości od 0 do –1,0) |
Przenieś w prawo | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (dla wartości od 0 do 1,0) |
Ten fragment kodu zawiera klasę pomocniczą, która pozwala sprawdzić oś kapelusza i wartości kodu klucza ze zdarzenia wejściowego w celu określenia kierunku pada kierunkowego.
Kotlin
class Dpad { private var directionPressed = -1 // initialized to -1 fun getDirectionPressed(event: InputEvent): Int { if (!isDpadDevice(event)) { return -1 } // If the input event is a MotionEvent, check its hat axis values. (event as? MotionEvent)?.apply { // Use the hat axis value to find the D-pad direction val xaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_X) val yaxis: Float = event.getAxisValue(MotionEvent.AXIS_HAT_Y) directionPressed = when { // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad // LEFT and RIGHT direction accordingly. xaxis.compareTo(-1.0f) == 0 -> Dpad.LEFT xaxis.compareTo(1.0f) == 0 -> Dpad.RIGHT // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad // UP and DOWN direction accordingly. yaxis.compareTo(-1.0f) == 0 -> Dpad.UP yaxis.compareTo(1.0f) == 0 -> Dpad.DOWN else -> directionPressed } } // If the input event is a KeyEvent, check its key code. (event as? KeyEvent)?.apply { // Use the key code to find the D-pad direction. directionPressed = when(event.keyCode) { KeyEvent.KEYCODE_DPAD_LEFT -> Dpad.LEFT KeyEvent.KEYCODE_DPAD_RIGHT -> Dpad.RIGHT KeyEvent.KEYCODE_DPAD_UP -> Dpad.UP KeyEvent.KEYCODE_DPAD_DOWN -> Dpad.DOWN KeyEvent.KEYCODE_DPAD_CENTER -> Dpad.CENTER else -> directionPressed } } return directionPressed } companion object { internal const val UP = 0 internal const val LEFT = 1 internal const val RIGHT = 2 internal const val DOWN = 3 internal const val CENTER = 4 fun isDpadDevice(event: InputEvent): Boolean = // Check that input comes from a device with directional pads. event.source and InputDevice.SOURCE_DPAD != InputDevice.SOURCE_DPAD } }
Java
public class Dpad { final static int UP = 0; final static int LEFT = 1; final static int RIGHT = 2; final static int DOWN = 3; final static int CENTER = 4; int directionPressed = -1; // initialized to -1 public int getDirectionPressed(InputEvent event) { if (!isDpadDevice(event)) { return -1; } // If the input event is a MotionEvent, check its hat axis values. if (event instanceof MotionEvent) { // Use the hat axis value to find the D-pad direction MotionEvent motionEvent = (MotionEvent) event; float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X); float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y); // Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad // LEFT and RIGHT direction accordingly. if (Float.compare(xaxis, -1.0f) == 0) { directionPressed = Dpad.LEFT; } else if (Float.compare(xaxis, 1.0f) == 0) { directionPressed = Dpad.RIGHT; } // Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad // UP and DOWN direction accordingly. else if (Float.compare(yaxis, -1.0f) == 0) { directionPressed = Dpad.UP; } else if (Float.compare(yaxis, 1.0f) == 0) { directionPressed = Dpad.DOWN; } } // If the input event is a KeyEvent, check its key code. else if (event instanceof KeyEvent) { // Use the key code to find the D-pad direction. KeyEvent keyEvent = (KeyEvent) event; if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) { directionPressed = Dpad.LEFT; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) { directionPressed = Dpad.RIGHT; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) { directionPressed = Dpad.UP; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) { directionPressed = Dpad.DOWN; } else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) { directionPressed = Dpad.CENTER; } } return directionPressed; } public static boolean isDpadDevice(InputEvent event) { // Check that input comes from a device with directional pads. if ((event.getSource() & InputDevice.SOURCE_DPAD) != InputDevice.SOURCE_DPAD) { return true; } else { return false; } } }
Możesz używać tej klasy pomocniczej w swojej grze wszędzie tam, gdzie chcesz przetwarzać dane z krzyżownicy (na przykład w funkcjach onGenericMotionEvent()
lub onKeyDown()
).
Na przykład:
Kotlin
private val dpad = Dpad() ... override fun onGenericMotionEvent(event: MotionEvent): Boolean { if (Dpad.isDpadDevice(event)) { when (dpad.getDirectionPressed(event)) { Dpad.LEFT -> { // Do something for LEFT direction press ... return true } Dpad.RIGHT -> { // Do something for RIGHT direction press ... return true } Dpad.UP -> { // Do something for UP direction press ... return true } ... } } // Check if this event is from a joystick movement and process accordingly. ... }
Java
Dpad dpad = new Dpad(); ... @Override public boolean onGenericMotionEvent(MotionEvent event) { // Check if this event if from a D-pad and process accordingly. if (Dpad.isDpadDevice(event)) { int press = dpad.getDirectionPressed(event); switch (press) { case LEFT: // Do something for LEFT direction press ... return true; case RIGHT: // Do something for RIGHT direction press ... return true; case UP: // Do something for UP direction press ... return true; ... } } // Check if this event is from a joystick movement and process accordingly. ... }
Przetwarzanie ruchów joysticka
Gdy gracz porusza joystickiem na kontrolerach do gier, Android przesyła zgłoszenie MotionEvent
, które zawiera kod działania ACTION_MOVE
i zaktualizowane pozycje osi joysticka. Gra może używać danych udostępnianych przez MotionEvent
, aby określić, czy nastąpiło zdarzenie, na którym jej zależy.
Pamiętaj, że zdarzenia ruchu steru mogą zawierać wiele próbek ruchu w ramach jednego obiektu. Obiekt MotionEvent
zawiera bieżącą pozycję każdej osi joysticka oraz wiele historycznych pozycji każdej osi. Gdy raportujesz zdarzenia ruchu z kodem działania ACTION_MOVE
(np. ruchy joysticka), Android grupowo zapisuje wartości osi w celu zwiększenia wydajności. Wartości historyczne osi to zbiór różnych wartości starszych niż bieżąca wartość osi i nowszych niż wartości zgłoszone w poprzednich zdarzeniach ruchu. Więcej informacji znajdziesz w materiałach referencyjnych MotionEvent
.
Korzystając z danych historycznych, możesz dokładniej renderować ruch obiektu w grze na podstawie danych z joysticka. Aby pobrać bieżące i historyczne wartości, wywołaj funkcję getAxisValue()
lub getHistoricalAxisValue()
. Liczba historycznych punktów jest też widoczna w zdarzeniu joysticka po wywołaniu funkcji getHistorySize()
.
Poniższy fragment kodu pokazuje, jak zastąpić wywołanie zwrotne onGenericMotionEvent()
, aby przetworzyć dane wejściowe joysticka. Najpierw przetwórz historyczne wartości osi, a potem jej bieżącą pozycję.
Kotlin
class GameView(...) : View(...) { override fun onGenericMotionEvent(event: MotionEvent): Boolean { // Check that the event came from a game controller return if (event.source and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK && event.action == MotionEvent.ACTION_MOVE) { // Process the movements starting from the // earliest historical position in the batch (0 until event.historySize).forEach { i -> // Process the event at historical position i processJoystickInput(event, i) } // Process the current movement sample in the batch (position -1) processJoystickInput(event, -1) true } else { super.onGenericMotionEvent(event) } } }
Java
public class GameView extends View { @Override public boolean onGenericMotionEvent(MotionEvent event) { // Check that the event came from a game controller if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) { // Process all historical movement samples in the batch final int historySize = event.getHistorySize(); // Process the movements starting from the // earliest historical position in the batch for (int i = 0; i < historySize; i++) { // Process the event at historical position i processJoystickInput(event, i); } // Process the current movement sample in the batch (position -1) processJoystickInput(event, -1); return true; } return super.onGenericMotionEvent(event); } }
Zanim użyjesz sterowania za pomocą joysticka, musisz określić, czy joystick jest wyśrodkowany, a następnie odpowiednio obliczyć ruchy jego osi. W przypadku joysticków zazwyczaj występuje płaski obszar, czyli zakres wartości zbliżonych do współrzędnych (0, 0), w których oś jest uważana za wyśrodkowaną. Jeśli wartość osi zgłaszanej przez Androida znajduje się w płaskim obszarze, ustaw kontroler w stanie spoczynku (czyli nie może się przemieszczać wzdłuż obu osi).
Fragment kodu poniżej zawiera metodę pomocniczą, która oblicza ruch wzdłuż każdej osi. Ten element pomocniczy wywołujesz w metodzie processJoystickInput()
opisanej poniżej.
Kotlin
private fun getCenteredAxis( event: MotionEvent, device: InputDevice, axis: Int, historyPos: Int ): Float { val range: InputDevice.MotionRange? = device.getMotionRange(axis, event.source) // A joystick at rest does not always report an absolute position of // (0,0). Use the getFlat() method to determine the range of values // bounding the joystick axis center. range?.apply { val value: Float = if (historyPos < 0) { event.getAxisValue(axis) } else { event.getHistoricalAxisValue(axis, historyPos) } // Ignore axis values that are within the 'flat' region of the // joystick axis center. if (Math.abs(value) > flat) { return value } } return 0f }
Java
private static float getCenteredAxis(MotionEvent event, InputDevice device, int axis, int historyPos) { final InputDevice.MotionRange range = device.getMotionRange(axis, event.getSource()); // A joystick at rest does not always report an absolute position of // (0,0). Use the getFlat() method to determine the range of values // bounding the joystick axis center. if (range != null) { final float flat = range.getFlat(); final float value = historyPos < 0 ? event.getAxisValue(axis): event.getHistoricalAxisValue(axis, historyPos); // Ignore axis values that are within the 'flat' region of the // joystick axis center. if (Math.abs(value) > flat) { return value; } } return 0; }
Po połączeniu wszystkich elementów widać, jak można przetwarzać ruchy joysticka w grze:
Kotlin
private fun processJoystickInput(event: MotionEvent, historyPos: Int) { val inputDevice = event.device // Calculate the horizontal distance to move by // using the input value from one of these physical controls: // the left control stick, hat axis, or the right control stick. var x: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos) if (x == 0f) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos) } if (x == 0f) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos) } // Calculate the vertical distance to move by // using the input value from one of these physical controls: // the left control stick, hat switch, or the right control stick. var y: Float = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos) if (y == 0f) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos) } if (y == 0f) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos) } // Update the ship object based on the new x and y values }
Java
private void processJoystickInput(MotionEvent event, int historyPos) { InputDevice inputDevice = event.getDevice(); // Calculate the horizontal distance to move by // using the input value from one of these physical controls: // the left control stick, hat axis, or the right control stick. float x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos); if (x == 0) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos); } if (x == 0) { x = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos); } // Calculate the vertical distance to move by // using the input value from one of these physical controls: // the left control stick, hat switch, or the right control stick. float y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos); if (y == 0) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos); } if (y == 0) { y = getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos); } // Update the ship object based on the new x and y values }
Aby obsługiwać kontrolery do gier, które mają bardziej zaawansowane funkcje niż pojedynczy joystick, postępuj zgodnie z tymi sprawdzonymi metodami:
- Obsługa 2 joysticków kontrolera. Wiele kontrolerów do gier ma zarówno lewy, jak i prawy joystick. W przypadku lewego drążka Android raportuje ruchy poziome jako zdarzenia
AXIS_X
, a ruchy pionowe jako zdarzeniaAXIS_Y
. W przypadku prawego drążka Android zgłasza ruchy poziome jako zdarzeniaAXIS_Z
, a ruchy pionowe jako zdarzeniaAXIS_RZ
. Pamiętaj, aby w kodzie obsługiwać oba drążki kontrolera. -
Obsługa naciśnięć bocznych przycisków spustowych (i upewnij się, że gra działa z wykorzystaniem zdarzeń
AXIS_
iKEYCODE_BUTTON_
). Niektóre kontrolery mają spusty po lewej i prawej krawędzi. Gdy te wyzwalacze są obecne, emitują zdarzenieAXIS_*TRIGGER
lubKEYCODE_BUTTON_*2
albo oba te zdarzenia. W przypadku lewego spustu są toAXIS_LTRIGGER
iKEYCODE_BUTTON_L2
. Prawidłowym aktywatorem jestAXIS_RTRIGGER
iKEYCODE_BUTTON_R2
. Zdarzenia związane z osią występują tylko wtedy, gdy aktywator wysyła zakres wartości od 0 do 1, a niektóre kontrolery z wyjściem analogowym generują zdarzenia związane z przyciskiem emisji, a także wtedy, gdy zdarzenia osi Aby zachować zgodność ze wszystkimi popularnymi kontrolerami gier, gry muszą obsługiwać zdarzeniaAXIS_
iKEYCODE_BUTTON_
, ale powinny preferować to zdarzenie, które ma największe znaczenie dla rozgrywki, jeśli kontroler zgłasza oba zdarzenia. W Androidzie 4.3 (poziom interfejsu API 18) i nowszych kontroler, który generujeAXIS_LTRIGGER
, przekazuje identyczną wartość na osiAXIS_BRAKE
. To samo dotyczy elementówAXIS_RTRIGGER
iAXIS_GAS
. Android raportuje wszystkie naciśnięcia analogowych przełączników z normalizowaną wartością od 0,0 (zwolnienie) do 1,0 (pełne naciśnięcie). -
Obejmuje to konkretne zachowania i obsługę w środowiskach emulowanych. Emulowane platformy, takie jak Gry Google Play, mogą się nieznacznie różnić pod względem działania w zależności od możliwości systemu operacyjnego hosta. Na przykład niektóre kontrolery, które emitują zdarzenia
AXIS_
iKEYCODE_BUTTON_
, emitują tylko zdarzeniaAXIS_
, a w przypadku niektórych innych kontrolerów obsługa może być całkowicie wyłączona.