ほとんどのゲームは 1 台の Android 搭載デバイスに対して 1 人のユーザーをサポートするように設計されていますが、1 台の Android 搭載デバイスに複数のゲーム コントローラを同時に接続することによって複数のユーザーをサポートすることも可能です。
このレッスンでは、1 台のデバイス上でのマルチプレーヤー型ゲームにおいて、接続されている複数のコントローラからの入力を処理するための基本的な手法について説明します。また、プレーヤーのアバターと各コントローラ デバイス間のマッピングを管理する方法と、コントローラの入力イベントを適切に処理する方法についても説明します。
プレーヤーをコントローラ デバイス ID にマッピングする
ゲーム コントローラが Android 搭載デバイスに接続されると、ゲーム コントローラに整数のデバイス ID が割り当てられます。InputDevice.getDeviceIds() を呼び出すことで、接続されているゲーム コントローラのデバイス ID を取得できます(ゲーム コントローラが接続されていることを確認するを参照)。これにより、各デバイス 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 を利用して、入力イベントの発生元のコントローラを特定し、そのコントローラに関連付けられているプレーヤーのアバターを更新します。
次のコード スニペットは、ゲーム コントローラのデバイス 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);
}