ほとんどのゲームは Android デバイスごとに 1 人のユーザーをサポートするように設計されていますが、同じ Android デバイスで同時に接続されたゲーム コントローラを使用して複数のユーザーをサポートすることもできます。
このレッスンでは、単一デバイスのマルチプレーヤー ゲームで、接続された複数のコントローラからの入力を処理する基本的な手法について説明します。これには、プレーヤーのアバターと各コントローラ デバイス間のマッピングの維持や、コントローラ入力イベントを適切に処理することが含まれます。
プレーヤーをコントローラ デバイス ID にマッピングする
ゲーム コントローラが Android デバイスに接続されると、システムによって整数のデバイス ID が割り当てられます。接続されているゲーム コントローラのデバイス ID を取得するには、ゲーム コントローラが接続されていることを確認するで説明されているように、InputDevice.getDeviceIds()
を呼び出します。これにより、各デバイス ID をゲーム内のプレーヤーに関連付けて、各プレーヤーのゲーム アクションを個別に処理できます。
注: Android 4.1(API レベル 16)以降を搭載したデバイスでは、入力デバイスに対して一意の永続的な文字列値を返す getDescriptor()
を使用して、入力デバイスの記述子を取得できます。デバイス ID とは異なり、入力デバイスの接続解除、再接続、再構成が行われても、記述子の値は変更されません。
以下のコード スニペットは、SparseArray
を使用してプレーヤーのアバターを特定のコントローラに関連付ける方法を示しています。この例では、mShips
変数に Ship
オブジェクトのコレクションが格納されます。新しいプレーヤー アバターは、ユーザーが新しいコントローラを追加するときにゲーム内で作成され、関連付けられているコントローラが削除されると削除されます。
onInputDeviceAdded()
および onInputDeviceRemoved()
コールバック メソッドは、
Android バージョン間でのコントローラのサポートで導入された抽象化レイヤの一部です。これらのリスナー コールバックを実装することで、コントローラが追加または削除されたときにゲーム コントローラのデバイス ID を識別できます。この検出は Android 2.3(API レベル 9)以降と互換性があります。
Kotlin
private val ships = SparseArray<Ship>() override fun onInputDeviceAdded(deviceId: Int) { getShipForID(deviceId) } override fun onInputDeviceRemoved(deviceId: Int) { removeShipForID(deviceId) } private fun getShipForID(shipID: Int): Ship { return ships.get(shipID) ?: Ship().also { ships.append(shipID, it) } } private fun removeShipForID(shipID: Int) { ships.remove(shipID) }
Java
private final SparseArray<Ship> ships = new SparseArray<Ship>(); @Override public void onInputDeviceAdded(int deviceId) { getShipForID(deviceId); } @Override public void onInputDeviceRemoved(int deviceId) { removeShipForID(deviceId); } private Ship getShipForID(int shipID) { Ship currentShip = ships.get(shipID); if ( null == currentShip ) { currentShip = new Ship(); ships.append(shipID, currentShip); } return currentShip; } private void removeShipForID(int shipID) { ships.remove(shipID); }
複数のコントローラからの入力を処理する
複数のコントローラからの入力を処理するために、ゲームで次のループを実行する必要があります。
- 入力イベントが発生したかどうかを検出します。
- 入力元とそのデバイス ID を特定します。
- 入力イベント キーコードまたは軸値で指定されたアクションに基づいて、そのデバイス ID に関連付けられているプレーヤーのアバターを更新します。
- ユーザー インターフェースをレンダリングして更新します。
KeyEvent
および MotionEvent
入力イベントにはデバイス ID が関連付けられています。ゲームではこの機能を利用して、入力イベントの送信元コントローラを特定し、そのコントローラに関連付けられたプレーヤー アバターを更新できます。
次のコード スニペットは、ゲーム コントローラのデバイス ID に対応するプレーヤーのアバターの参照を取得し、ユーザーがそのコントローラのボタンを押すたびにゲームを更新する方法を示しています。
Kotlin
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { if (event.source and InputDevice.SOURCE_GAMEPAD == InputDevice.SOURCE_GAMEPAD) { event.deviceId.takeIf { it != -1 }?.also { deviceId -> val currentShip: Ship = getShipForID(deviceId) // Based on which key was pressed, update the player avatar // (e.g. set the ship headings or fire lasers) return true } } return super.onKeyDown(keyCode, event) }
Java
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if ((event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { int deviceId = event.getDeviceId(); if (deviceId != -1) { Ship currentShip = getShipForId(deviceId); // Based on which key was pressed, update the player avatar // (e.g. set the ship headings or fire lasers) ... return true; } } return super.onKeyDown(keyCode, event); }
注: ユーザーのゲーム コントローラが切断された場合は、ゲームを一時停止して、再接続を希望するかどうかを尋ねることをおすすめします。