コントローラには次の 2 種類のアクションがあります。
- オンとオフのバイナリ状態を持つボタンに使用される
KeyEvent - 値の範囲を返す軸に使用される
MotionEvent。アナログスティックの場合は -1 ~ 1、アナログ トリガーの場合は 0 ~ 1 など。
これらの入力は、focus を持つ View から読み取ることができます。
MotionEventに対してonGenericMotionEventが引き上げられます。
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
if (event.isFromSource(SOURCE_GAMEPAD)
&& event.repeatCount == 0
) {
Log.d("GameView", "Gamepad key pressed: $keyCode")
return true
}
return super.onKeyDown(keyCode, event)
}
override fun onGenericMotionEvent(event: MotionEvent): Boolean {
if (event.isFromSource(SOURCE_JOYSTICK)) {
Log.d("GameView", "Gamepad event: $event")
return true
}
return super.onGenericMotionEvent(event)
}
Java
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.isFromSource(SOURCE_GAMEPAD)
&& event.getRepeatCount() == 0
) {
Log.d("GameView", "Gamepad key pressed: " + keyCode);
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (event.isFromSource(SOURCE_JOYSTICK)) {
Log.d("GameView", "Gamepad event: " + event);
return true;
}
return super.onGenericMotionEvent(event);
}
必要に応じて、代わりに Activity から直接イベントを読み取ることができます。
MotionEventのdispatchGenericMotionEventが引き上げられますKeyEventに対してdispatchKeyEventが引き上げられます。
ゲーム コントローラが接続されていることを確認する
入力イベントをレポートする際、Android は異なる入力デバイス タイプに対して同じキーまたは軸の ID を再利用します。たとえば、タッチ スクリーンの操作ではタッチ面の X 座標を表す AXIS_X イベントが生成されますが、ゲームパッドの操作では左スティックの X 位置を表す AXIS_X イベントが生成されます。つまり、入力イベントを正しく解釈するには、ソースタイプを確認する必要があります。
接続されている InputDevice がゲーム コントローラであることを確認するには、supportsSource(int) 関数を使用します。
- ソースタイプ
SOURCE_GAMEPADは、入力デバイスにコントローラ ボタン(KEYCODE_BUTTON_Aなど)があることを示します。このソースタイプは厳密には、ゲーム コントローラに D-pad ボタンがあるかどうかは示しませんが、ほとんどのコントローラには通常、方向コントロールが搭載されています。 - ソースタイプ
SOURCE_DPADは、入力デバイスに D-pad ボタン(DPAD_UPなど)があることを示します。 - ソースタイプ
SOURCE_JOYSTICKは、入力デバイスにアナログのコントロール スティック(AXIS_XとAXIS_Yに沿った動きを記録するジョイスティックなど)があることを示します。
次のコード スニペットは、接続されている入力デバイスがゲーム コントローラかどうかを確認するためのヘルパー メソッドを示しています。ゲーム コントローラの場合、このメソッドはゲーム コントローラのデバイス ID を取得します。これにより、各デバイス ID をゲームのプレーヤーに関連付けて、接続されている各プレーヤーのゲーム アクションを個別に処理することができます。1 台の 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 (supportsSource(SOURCE_GAMEPAD)
|| supportsSource(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);
if (dev == null) {
continue;
}
// Verify that the device has gamepad buttons, control sticks, or both.
if (dev.supportsSource(SOURCE_GAMEPAD) || dev.supportsSource(SOURCE_JOYSTICK)) {
// This device is a game controller. Store its device ID.
if (!gameControllerDeviceIds.contains(deviceId)) {
gameControllerDeviceIds.add(deviceId);
}
}
}
return gameControllerDeviceIds;
}
コントローラの入力を処理する
このセクションでは、Android でサポートされているゲーム コントローラのタイプについて説明します。
C++ デベロッパーは、ゲーム コントローラ ライブラリを使用する必要があります。すべてのコントローラを最も一般的な機能のサブセットに統合し、ボタン レイアウトを検出する機能など、コントローラ間の一貫したインターフェースを提供します。
この図は、Android ゲーム デベロッパーが Android での一般的なコントローラの外観を想定できることを示しています。
この表に、ゲーム コントローラの標準イベント名とタイプを示します。イベントの完全なリストについては、一般的なバリエーションをご覧ください。システムは、onGenericMotionEvent と KeyEvent のイベントを onKeyDown と onKeyUp を通して送信します。MotionEvent
| コントローラの入力 | KeyEvent | MotionEvent |
|---|---|---|
| 1. D-Pad |
AXIS_HAT_X(横方向の入力) AXIS_HAT_Y(縦方向の入力) |
|
| 2. 左アナログスティック |
KEYCODE_BUTTON_THUMBL(押されている場合) |
AXIS_X(水平方向の移動) AXIS_Y(垂直方向の移動) |
| 3. 右アナログスティック |
KEYCODE_BUTTON_THUMBR(押されている場合) |
AXIS_Z(水平方向の移動) AXIS_RZ(垂直方向の移動) |
| 4. X ボタン | KEYCODE_BUTTON_X |
|
| 5. A ボタン | KEYCODE_BUTTON_A |
|
| 6. Y ボタン | KEYCODE_BUTTON_Y |
|
| 7. B ボタン | KEYCODE_BUTTON_B |
|
| 8. 右バンパー |
KEYCODE_BUTTON_R1 |
|
| 9. 右トリガー |
AXIS_RTRIGGER |
|
| 10. 左トリガー | AXIS_LTRIGGER |
|
| 11. 左バンパー | KEYCODE_BUTTON_L1 |
|
| 12. 開始 | KEYCODE_BUTTON_START |
|
| 13. 選択 | KEYCODE_BUTTON_SELECT |
ボタンの押下を処理する
Android はコントローラのボタンの押下をキーボードのボタンの押下とまったく同様に報告するため、次の処理を行う必要があります。
- イベントが
SOURCE_GAMEPADから送信されていることを検証します。 KeyEvent.getRepeatCount()を使用してボタンを 1 回だけ受信するようにしてください。Android は、キーボードのキーを長押しした場合と同様に、キーイベントを繰り返して送信します。- イベントが処理されたことを示すには、
trueを返します。 処理されないイベントを
superに渡し、Android のさまざまな互換性レイヤが適切に機能することを確認します。Kotlin
class GameView : View { // ... override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { event.apply { var handled = false // make sure we're handling gamepad events if (isFromSource(SOURCE_GAMEPAD)) { // avoid processing the keycode repeatedly if (repeatCount == 0) { when (keyCode) { // handle the "A" button KEYCODE_BUTTON_A -> { handled = true } } // ... } } if (handled) { return true } } return super.onKeyDown(keyCode, event) } }Java
public class GameView extends View { // ... @Override public boolean onKeyDown(int keyCode, KeyEvent event) { boolean handled = false; // make sure we're handling gamepad events if (event.isFromSource(SOURCE_GAMEPAD)) { // avoid processing the keycode repeatedly if (event.getRepeatCount() == 0) { switch (keyCode) { case KEYCODE_BUTTON_A: // handle the "A" button handled = true; break; // ... } } // mark this event as handled if (handled) { return true; } } // Always do this instead of "return false" // it allows Android's input compatibility layers to work return super.onKeyDown(keyCode, event); } }
十字キーの入力を処理する
4 方向の十字キー(D-pad)は、多くのゲーム コントローラで一般的な物理コントロールとして使用されています。Android は、D-pad の UP と DOWN の押下を AXIS_HAT_Y イベントとしてレポートします。-1.0 は上、1.0 は下を示します。D-pad の LEFT または RIGHT の押下を AXIS_HAT_X イベントとしてレポートします。-1.0 は左、1.0 は右を示します。
D-pad の押下をキーコードでレポートするコントローラもあります。ゲームで D-pad の押下を処理する場合、表 2 に示すように、ハット軸のイベントと D-pad のキーコードを同じ入力イベントとして処理する必要があります。
表 2. D-pad のキーコードとハット軸の値として推奨されるデフォルトのゲーム アクション
| ゲーム アクション | D-pad のキーコード | ハット軸のコード |
|---|---|---|
| 上に移動 | 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-pad の方向を決定するためのヘルパークラスを示しています。
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.
return event.isFromSource(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.
return event.isFromSource(InputDevice.SOURCE_DPAD);
}
}
このヘルパークラスは、ゲームで D-pad の入力を処理する場合に使用できます(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.
...
}
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.
...
}
ジョイスティックの動きを処理する
プレーヤーがゲーム コントローラのジョイスティックを動かすと、Android が ACTION_MOVE アクション コードとジョイスティックの軸の最新の位置を含む MotionEvent をレポートします。ゲームは MotionEvent から提供されたデータを使用して、処理対象のジョイスティックの動きが行われたかどうかを判断します。
ジョイスティックのモーション イベントは、複数の動きのサンプルを 1 つのオブジェクトにまとめることがあるので注意してください。MotionEvent オブジェクトには、ジョイスティックの各軸の現在の位置情報と、各軸のこれまでの各種位置情報が格納されます。アクション コード ACTION_MOVE(ジョイスティックの動きなど)でモーション イベントをレポートする場合、Android は効率性向上のために軸の値をまとめて処理します。軸のこれまでの値は、現在の軸の値より古い個別の値セットと、以前のモーション イベントでレポートされた値より最近の値で構成されます。詳しくは、MotionEvent のリファレンスをご覧ください。
ジョイスティックの入力に基づいてゲーム オブジェクトの動きを正確にレンダリングするには、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)
}
}
}
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);
}
}
ジョイスティックの入力を使用する前に、ジョイスティックの位置が中心かどうかを確認し、それに応じて軸の動きを計算する必要があります。通常、ジョイスティックには「フラット」な領域(軸の位置が中心とみなされる座標(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
}
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;
}
まとめると、ジョイスティックの動きをゲーム内で処理する方法は次のとおりです。
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
}
1 つのジョイスティックでは実現できない高度な機能を備えたゲーム コントローラをサポートするには、以下のベスト プラクティスに従います。
- デュアル コントローラ スティックに対応する。多くのゲーム コントローラには左右にジョイスティックがあります。左スティックについては、水平方向の動きを
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 Games などのエミュレートされたプラットフォームは、ホスト オペレーティング システムの機能に基づいて動作が若干異なる場合があります。たとえば、
AXIS_イベントとKEYCODE_BUTTON_イベントの両方を送信する一部のコントローラはAXIS_イベントのみを送信し、一部のコントローラは完全にサポートされていない可能性があります。
一般的なバリエーション
Android ではコントローラに対するサポートが多岐にわたるため、ゲームがプレーヤーベースでバグなく動作することを検証するためのビルドとテストの方法がわかりにくい場合があります。一見するとさまざまなコントローラがあるように見えますが、世界中のコントローラ メーカーは、3 種類のコントローラ スタイルを常に採用する傾向があります。一部のデバイスでは、これらの 2 つ以上を切り替えるハードウェア トグルが用意されています。
つまり、開発チーム内で 3 つのコントローラでテストするだけで、許可リストや拒否リストを使用しなくてもゲームをプレイできることを確認できます。
一般的なコントローラの種類
コントローラの最も一般的なスタイルは、人気のあるゲーム機のレイアウトを模倣する傾向があります。ボタンラベルとレイアウトの美しさだけでなく、発生するイベントの機能性も考慮されています。ハードウェアでコンソールの種類を切り替えるコントローラは、送信するイベントを変更し、論理ボタンのレイアウトも変更することがよくあります。
テストの際は、各カテゴリのコントローラ 1 つでゲームが動作することを確認することをおすすめします。ファーストパーティ コントローラまたは人気のサードパーティ メーカーでテストすることを選択できます。一般的に、最も人気のあるコントローラは、ベスト エフォートで上記の定義にマッピングされます。
| コントローラタイプ | 動作の違い | ラベル付けのバリエーション |
|---|---|---|
| Xbox スタイルのコントローラ
通常、Microsoft Xbox と Windows* プラットフォーム向けに作られたコントローラです。 |
これらのコントローラは、プロセス コントローラの入力で説明されている機能セットに一致します。 | これらのコントローラの L2/R2 ボタンには LT/RT というラベルが付いています。 |
| Switch Style Controllers
これらのコントローラは通常、Nintendo Switch* ファミリーのコンソール向けに設計されています。 |
これらのコントローラは KeyEvent
KEYCODE_BUTTON_R2
KEYCODE_BUTTON_L2
MotionEvent を送信します。 |
これらのコントローラの L2/R2 ボタンには ZL/ZR というラベルが付いています。 これらのコントローラでは、A ボタンと B ボタン、X ボタンと Y ボタンも入れ替わるため、 |
| PlayStation スタイルのコントローラ
これらのコントローラは通常、Sony PlayStation* ファミリーのコンソール向けに設計されています。 |
これらのコントローラは、Xbox スタイルのコントローラのように MotionEvent を送信しますが、完全に押し下げると Switch スタイルのコントローラのように KeyEvent も送信します。 |
これらのコントローラでは、フェイスボタンに異なるグリフのセットが使用されています。 |
* Microsoft、Xbox、Windows は Microsoft の登録商標です。 Nintendo Switch は Nintendo of America Inc. の登録商標です。 PlayStation は Sony Interactive Entertainment Inc. の登録商標です。
トリガーボタンの曖昧さを解消
コントローラによっては AXIS_LTRIGGER と AXIS_RTRIGGER を送信するものもあれば、KEYCODE_BUTTON_L2 と KEYCODE_BUTTON_R2 を送信するものもあり、ハードウェアの機能に基づいてこれらのイベントをすべて送信するものもあります。これらのイベントをすべてサポートすることで、互換性を最大限に高めます。
AXIS_LTRIGGER を送信するすべてのコントローラは AXIS_BRAKE も送信します。同様に、AXIS_RTRIGGER と AXIS_GAS も送信します。これにより、レーシング ホイールと一般的なゲーム コントローラ間の互換性を最大限に高めることができます。通常、これにより問題が発生することはありませんが、キーの再マッピング画面などの機能では注意が必要です。
| トリガー | MotionEvent |
KeyEvent |
|---|---|---|
| 左トリガー | AXIS_LTRIGGERAXIS_BRAKE
|
KEYCODE_BUTTON_L2
|
| 右トリガー | AXIS_RTRIGGERAXIS_GAS
|
KEYCODE_BUTTON_R2
|
できるだけ多くのコントローラとの互換性を維持し、イベントが重複排除されるように、ゲームが KeyEvent と MotionEvent の両方を処理できることを確認する必要があります。
サポートされているコントローラ
テストの際は、各カテゴリのコントローラ 1 つでゲームが動作することを確認することをおすすめします。
- Xbox スタイル
- Nintendo Switch のスタイル
- PlayStation スタイル
ファーストパーティ コントローラや一般的なサードパーティ メーカーのコントローラでテストできます。一般的に、最も一般的なコントローラは定義にできるだけ忠実にマッピングされます。