여러 게임 컨트롤러 지원

대부분의 게임은 Android 기기당 단일 사용자를 지원하도록 설계되었지만, 동일한 Android 기기에 동시에 연결된 게임 컨트롤러를 사용하여 여러 사용자를 지원할 수도 있습니다.

이 과정에서는 연결된 여러 컨트롤러에서 단일 기기 멀티플레이어 게임의 입력을 처리하기 위한 몇 가지 기본 기법을 다룹니다. 여기에는 플레이어 아바타와 각 컨트롤러 기기 간의 매핑을 유지하고 컨트롤러 입력 이벤트를 적절하게 처리하는 작업이 포함됩니다.

플레이어를 컨트롤러 기기 ID에 매핑

게임 컨트롤러가 Android 기기에 연결되면 시스템은 정수로 된 기기 ID를 할당합니다. 게임 컨트롤러가 연결되어 있는지 확인에서와 같이 InputDevice.getDeviceIds()를 호출하여 연결된 게임 컨트롤러의 기기 ID를 가져올 수 있습니다. 그런 다음 각 기기 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);
}

여러 컨트롤러 입력 처리

게임은 여러 컨트롤러의 입력을 처리하려면 다음 루프를 실행해야 합니다.

  1. 입력 이벤트가 발생했는지 감지합니다.
  2. 입력 소스와 기기 ID를 확인합니다.
  3. 입력 이벤트 키 코드 또는 축 값이 나타내는 작업에 따라 기기 ID와 연결된 플레이어 아바타를 업데이트합니다.
  4. 사용자 인터페이스를 렌더링하고 업데이트합니다.

KeyEventMotionEvent 입력 이벤트에는 연결된 기기 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);
}

참고: 사용자의 게임 컨트롤러가 연결 해제되면 게임을 일시중지하고 사용자에게 다시 연결할지 묻는 것이 좋습니다.