시스템 수준에서 Android는 게임 컨트롤러의 입력 이벤트 코드를 Android 키 코드와 축 값으로 보고합니다. 게임에서 이러한 코드와 값을 받아 특정 인게임 작업으로 변환할 수 있습니다.
플레이어가 게임 컨트롤러를 Android 지원 기기에 물리적으로 연결하거나 무선으로 페어링하면 시스템은 컨트롤러를 입력 기기로 자동 감지하고 입력 이벤트를 보고하기 시작합니다. 게임은 활성 상태의 Activity
또는 포커스 View
에 다음 콜백 메서드를 구현하여 이러한 입력 이벤트를 받을 수 있습니다. 콜백은 Activity
또는 View
중 한 곳에만 구현해야 합니다.
Activity
님이 보낸 메시지:dispatchGenericMotionEvent(android.view. MotionEvent)
조이스틱 움직임과 같은 일반적인 모션 이벤트를 처리하기 위해 호출됩니다.
dispatchKeyEvent(android.view.KeyEvent)
게임패드 또는 D패드 버튼을 눌렀다가 떼는 동작과 같은 키 이벤트를 처리하기 위해 호출됩니다.
View
님이 보낸 메시지:onGenericMotionEvent(android.view.MotionEvent)
조이스틱 움직임과 같은 일반적인 모션 이벤트를 처리하기 위해 호출됩니다.
onKeyDown(int, android.view.KeyEvent)
게임패드 또는 D패드 버튼과 같은 물리적 키를 누르는 동작을 처리하기 위해 호출됩니다.
onKeyUp(int, android.view.KeyEvent)
게임패드 또는 D패드 버튼과 같은 실제 키의 해제를 처리하기 위해 호출됩니다.
권장되는 접근 방식은 사용자가 상호작용하는 특정 View
객체에서 이벤트를 캡처하는 것입니다.
콜백에서 제공한 다음 객체를 검사하여 수신된 입력 이벤트 유형에 관한 정보를 가져옵니다.
KeyEvent
- 방향 패드(D패드) 및 게임패드의 버튼 이벤트를 나타내는 객체입니다. 키 이벤트에는 트리거된 특정 버튼을 나타내는 키 코드(예:
DPAD_DOWN
또는BUTTON_A
)가 수반됩니다.getKeyCode()
를 호출하거나onKeyDown()
같은 키 이벤트 콜백을 통해 키 코드를 가져올 수 있습니다. MotionEvent
- 조이스틱 및 숄더 트리거 동작의 입력을 나타내는 객체입니다. 모션 이벤트는 작업 코드와 축 값 집합이 수반됩니다. 작업 코드는 조이스틱이 이동하는 등 발생한 상태 변경을 지정합니다. 축 값은 특정 물리적 컨트롤의 위치 및 기타 이동 속성(예:
AXIS_X
또는AXIS_RTRIGGER
)을 설명합니다. 작업 코드를 가져오려면getAction()
를 호출하고getAxisValue()
를 호출하여 축 값을 가져올 수 있습니다.
이 과정에서는 위에서 언급한 View
콜백 메서드를 구현하고 KeyEvent
및 MotionEvent
객체를 처리하여 게임 화면에서 가장 일반적인 유형의 물리적 컨트롤 (게임패드 버튼, 방향 패드, 조이스틱)의 입력을 처리하는 방법을 중점적으로 설명합니다.
게임 컨트롤러가 연결되어 있는지 확인
입력 이벤트를 보고할 때 Android는 게임 컨트롤러가 아닌 기기에서 발생한 이벤트와 게임 컨트롤러에서 발생한 이벤트를 구별하지 않습니다. 예를 들어 터치 스크린 작업은 터치 표면의 X 좌표를 나타내는 AXIS_X
이벤트를 생성하지만 조이스틱은 조이스틱의 X 위치를 나타내는 AXIS_X
이벤트를 생성합니다. 게임에서 게임 컨트롤러 입력을 처리하려고 하면 먼저 입력 이벤트가 관련된 소스 유형에서 발생하는지 확인해야 합니다.
연결된 입력 기기가 게임 컨트롤러인지 확인하려면 getSources()
를 호출하여 기기에서 지원하는 입력 소스 유형의 결합된 비트 필드를 가져옵니다. 그런 다음 아래 필드가 설정되어 있는지 확인하기 위해 테스트할 수 있습니다.
SOURCE_GAMEPAD
의 소스 유형은 입력 기기에 게임패드 버튼(예:BUTTON_A
)이 있음을 나타냅니다. 이 소스 유형은 게임 컨트롤러에 D패드 버튼이 있는지 확실히 표시하지 않습니다. 다만 대부분의 게임패드에는 일반적으로 방향 컨트롤이 있습니다.SOURCE_DPAD
의 소스 유형은 입력 기기에 D패드 버튼이 있음을 나타냅니다 (예:DPAD_UP
).SOURCE_JOYSTICK
의 소스 유형은 입력 기기에 아날로그 컨트롤 스틱(예:AXIS_X
및AXIS_Y
를 따라 이동을 기록하는 조이스틱)이 있음을 나타냅니다.
다음 코드 스니펫은 연결된 입력 기기가 게임 컨트롤러인지 확인할 수 있는 도우미 메서드를 보여줍니다. 입력 기기가 게임 컨트롤러라면 이 메서드는 게임 컨트롤러의 기기 ID를 가져옵니다. 그런 다음 각 기기 ID를 게임 플레이어와 연결하고 연결된 각 플레이어의 게임 작업을 별도로 처리할 수 있습니다. 동일한 Android 기기에 동시에 연결된 여러 게임 컨트롤러를 지원하는 방법에 관한 자세한 내용은 여러 게임 컨트롤러 지원을 참고하세요.
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 }
자바
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; }
또한 연결된 게임 컨트롤러에서 지원하는 개별 입력 기능도 확인할 수 있습니다. 예를 들어 게임이 이해하는 물리적 컨트롤 집합의 입력만 사용하도록 하려는 경우 유용할 수 있습니다.
연결된 게임 컨트롤러에서 특정 키 코드 또는 축 코드를 지원하는지 감지하려면 다음 기법을 사용하세요.
- Android 4.4 (API 수준 19) 이상에서는
hasKeys(int...)
를 호출하여 키 코드가 연결된 게임 컨트롤러에서 지원되는지 확인할 수 있습니다. - Android 3.1(API 수준 12) 이상에서는 먼저
getMotionRanges()
를 호출하여 연결된 게임 컨트롤러에서 지원하는 모든 사용 가능한 축을 찾을 수 있습니다. 그런 다음 반환된 각InputDevice.MotionRange
객체에서getAxis()
를 호출하여 축 ID를 가져옵니다.
게임패드 버튼 누름 처리
그림 1은 Android가 키 코드와 축 값을 대부분의 게임 컨트롤러의 물리적 컨트롤에 매핑하는 방법을 보여줍니다.
그림에서 번호는 다음을 가리킵니다.
게임패드 버튼이 눌릴 때 발생하는 공통 키 코드는 BUTTON_A
, BUTTON_B
, BUTTON_SELECT
, BUTTON_START
를 포함합니다. 일부 게임 컨트롤러는 D패드 크로스바의 중앙을 누르면 DPAD_CENTER
키 코드도 트리거합니다. 게임은 getKeyCode()
를 호출하거나 onKeyDown()
같은 키 이벤트 콜백을 통해서 키 코드를 검사할 수 있고 그 키 코드가 게임과 관련된 이벤트를 나타낸다면 게임 작업으로 처리할 수 있습니다. 표 1에는 가장 일반적인 게임패드 버튼에 권장되는 게임 작업이 나열되어 있습니다.
게임 작업 | 버튼 키 코드 |
---|---|
메인 메뉴에서 게임을 시작하거나 게임 중 일시중지 또는 일시중지 해제 | BUTTON_START * |
메뉴 표시 | BUTTON_SELECT * 및 KEYCODE_MENU * |
탐색 디자인 가이드에 설명된 Android 뒤로 탐색 동작과 동일합니다. | KEYCODE_BACK |
메뉴에서 이전 항목으로 돌아가기 | BUTTON_B |
선택을 확인하거나 기본 게임 작업 실행 | BUTTON_A 및 DPAD_CENTER |
* 게임에서 시작, 선택, 메뉴 버튼이 있어야 합니다.
도움말: 사용자가 게임 작업에 고유한 게임 컨트롤러 매핑을 맞춤설정하도록 게임에 구성 화면을 제공하세요.
다음 스니펫은 onKeyDown()
를 재정의하여 BUTTON_A
및 DPAD_CENTER
버튼 누름을 게임 작업과 연결하는 방법을 보여줍니다.
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 }
자바
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; } }
참고: Android 4.2 (API 수준 17) 이하에서는 시스템이 기본적으로 BUTTON_A
를 Android 뒤로 키로 취급합니다. 앱이 이 버전의 Android를 지원하는 경우 BUTTON_A
를 기본 게임 작업으로 처리해야 합니다. 기기에서 현재 Android SDK 버전을 확인하려면 Build.VERSION.SDK_INT
값을 참고하세요.
방향 패드 입력 처리
4방향 패드(D패드)는 많은 게임 컨트롤러에서 일반적인 물리적 컨트롤입니다. Android에서는 D패드의 위쪽 및 아래쪽 누르기를 AXIS_HAT_Y
이벤트로 보고하고, D패드의 왼쪽 또는 오른쪽 누르기는 -1.0(왼쪽)~1.0(오른쪽) 범위의 AXIS_HAT_X
이벤트로 보고합니다.
일부 컨트롤러는 D패드가 눌렸을 때 이벤트 대신 키 코드로 보고합니다. 게임에서 D패드 눌림을 감지해야 한다면 표 2에서 권장하는 것과 같이 해트 축 이벤트와 D패드 키 코드를 동일한 입력 이벤트로 취급해야 합니다.
게임 작업 | D패드 키 코드 | 해트 축 코드 |
---|---|---|
위로 이동 | KEYCODE_DPAD_UP |
AXIS_HAT_Y (0 ~ -1.0의 값을 가짐) |
아래로 이동 | KEYCODE_DPAD_DOWN |
AXIS_HAT_Y (0 ~ 1.0의 값을 가짐) |
왼쪽으로 이동 | KEYCODE_DPAD_LEFT |
AXIS_HAT_X (0 ~ -1.0의 값을 가짐) |
오른쪽으로 이동 | KEYCODE_DPAD_RIGHT |
AXIS_HAT_X (0 ~ 1.0의 값을 가짐) |
다음 코드 스니펫은 입력 이벤트에서 해트 축 및 키 코드 값을 확인하여 D패드 방향을 결정하도록 도와주는 클래스 사용법을 보여줍니다.
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 } }
자바
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; } } }
게임에서 D패드 입력을 처리할 때(예: onGenericMotionEvent()
또는 onKeyDown()
콜백에서) 이 도우미 클래스를 사용할 수 있습니다.
예를 들면 다음과 같습니다.
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. ... }
자바
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. ... }
조이스틱 이동 처리
플레이어가 게임 컨트롤러에서 조이스틱을 움직이면 Android는 ACTION_MOVE
작업 코드와 조이스틱 축의 업데이트된 위치가 포함된 MotionEvent
를 보고합니다. 게임은 MotionEvent
에서 제공하는 데이터를 사용하여 게임에 의미있는 조이스틱 이동이 발생했는지 확인할 수 있습니다.
조이스틱 모션 이벤트는 단일 객체 내에서 여러 이동 샘플을 함께 일괄 처리할 수 있습니다. MotionEvent
객체에는 각 축의 여러 이전 위치와 함께 각 조이스틱 축의 현재 위치가 포함됩니다. Android는 작업 코드가 ACTION_MOVE
인 모션 이벤트 (예: 조이스틱 이동)를 보고할 때 효율성을 위해 축 값을 일괄 처리합니다. 축의 과거 값은 현재 축 값보다 오래된 고유한 값의 집합과 이전 모션 이벤트에서 보고된 값보다 더 최근 값으로 구성됩니다. 자세한 내용은 MotionEvent
참조를 확인하세요.
이전 정보를 사용하면 조이스틱 입력에 기반한 게임 개체의 이동을 더 정확하게 렌더링할 수 있습니다. 현재 값과 이전 값을 가져오려면 getAxisValue()
또는 getHistoricalAxisValue()
를 호출하세요. getHistorySize()
를 호출하여 조이스틱 이벤트의 이전 지점 수를 확인할 수도 있습니다.
다음 스니펫은 onGenericMotionEvent()
콜백을 재정의하여 조이스틱 입력을 처리하는 방법을 보여줍니다. 먼저 축의 이전 값을 처리한 다음 현재 위치를 처리해야 합니다.
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) } } }
자바
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); } }
조이스틱 입력을 사용하기 전에 조이스틱이 중앙에 있는지 확인한 다음 그에 따라 축 이동을 계산해야 합니다. 조이스틱에는 일반적으로 평면 영역이 있습니다. 즉, 축이 중앙에 있는 것으로 간주되는 (0,0) 좌표 근처의 값 범위입니다. Android에서 보고한 축 값이 평평한 영역 내에 있으면 컨트롤러를 정지 상태로 취급해야 합니다 (즉, 두 축을 따라 움직이지 않음).
아래 스니펫은 각 축을 따라 이동하는 것을 계산하는 도우미 메서드를 보여줍니다. 아래에서 추가로 설명한 것과 같이 processJoystickInput()
메서드에서 이 도우미 메서드를 호출합니다.
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 }
자바
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; }
요약하자면 게임에서 조이스틱 이동을 처리하는 방법은 다음과 같습니다.
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 }
자바
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 }
단일 조이스틱 이상의 정교한 기능을 갖춘 게임 컨트롤러를 지원하려면 다음 권장사항을 따르세요.
- 듀얼 컨트롤러 스틱의 처리. 많은 게임 컨트롤러에는 왼쪽과 오른쪽 조이스틱이 모두 있습니다. Android는 왼쪽 스틱의 수평 이동은
AXIS_X
이벤트로, 수직 이동은AXIS_Y
이벤트로 보고합니다. 오른쪽 스틱의 경우 수평 이동은AXIS_Z
이벤트로, 수직 이동은AXIS_RZ
이벤트로 보고합니다. 코드에서 두 컨트롤러 스틱을 모두 처리해야 합니다. -
어깨 트리거 누르기를 처리하고 게임이
AXIS_
및KEYCODE_BUTTON_
이벤트와 호환되는지 확인합니다. 일부 컨트롤러에는 왼쪽 및 오른쪽 숄더 트리거가 있습니다. 이러한 트리거가 있으면AXIS_*TRIGGER
또는KEYCODE_BUTTON_*2
이벤트 또는 둘 다를 내보냅니다. 왼쪽 트리거의 경우AXIS_LTRIGGER
및KEYCODE_BUTTON_L2
입니다. 올바른 트리거의 경우AXIS_RTRIGGER
및KEYCODE_BUTTON_R2
입니다. 축 이벤트는 트리거가 0과 1 사이의 값 범위를 내보내는 경우에만 발생하며, 아날로그 출력이 있는 일부 컨트롤러는 축 이벤트 외에 버튼 이벤트도 내보냅니다. 게임은 모든 일반적인 게임 컨트롤러와 호환되기 위해AXIS_
및KEYCODE_BUTTON_
이벤트를 모두 지원해야 하지만, 컨트롤러가 둘 다 보고하는 경우 게임플레이에 가장 적합한 이벤트를 선택합니다. Android 4.3(API 수준 18) 이상에서는AXIS_LTRIGGER
를 생성하는 컨트롤러가AXIS_BRAKE
축의 동일한 값도 보고합니다.AXIS_RTRIGGER
와AXIS_GAS
의 경우도 마찬가지입니다. Android는 모든 아날로그 트리거가 눌렸을 때 0.0(해제)에서 1.0(완전히 눌림)으로 완전히 정규화된 값을 보고합니다. -
에뮬레이션된 환경에서는 특정 동작과 지원이 다를 수 있습니다. Google Play 게임즈와 같은 에뮬레이션된 플랫폼은 호스트 운영체제의 기능에 따라 동작이 약간 다를 수 있습니다. 예를 들어
AXIS_
및KEYCODE_BUTTON_
이벤트를 모두 내보내는 일부 컨트롤러는AXIS_
이벤트만 내보내며 일부 컨트롤러에 대한 지원이 완전히 누락될 수 있습니다.