コントローラのその他の機能

ゲーム コントローラには、プレーヤーの操作性と没入感を大幅に高める追加機能が搭載されています。Android ゲーム コントローラのハプティクス、モーション センサー、ライトの機能は、ゲーム エクスペリエンスを深め、豊かにするうえで特に役立ちます。各機能はプレーヤーの感覚を独自に刺激し、ゲーム内でのより有意義で直感的な操作を促進します。

アプリがゲーム コントローラをサポートしていることを宣言するには、アプリ マニフェストに android.hardware.gamepad 機能を追加します。

<manifest ...>
  ...
  <uses-feature android:name="android.hardware.gamepad" android:required="false"/>
  ...
</manifest>

ハプティクス

Android ゲーム コントローラのハプティクス機能は、ゲームプレイ中にリアルな触覚フィードバックを提供する重要なテクノロジーです。

ハプティクス技術は、振動や動きを通じて物理的な感覚をユーザーに伝えます。たとえば、ゲーム内で爆発が起こると、コントローラが振動し、プレーヤーは衝撃をリアルに感じることができます。また、微妙な振動をキャラクターの歩行や走行の音と同期させることで、よりリアルな体験を提供できます。このタイプの触覚フィードバックにより、プレーヤーはゲーム内で発生するさまざまなイベントを物理的に感じることができます。

このテクノロジーは、プレーヤーの没入感を最大限に高め、感情的な反応を増幅させ、ゲームのダイナミクスを豊かにします。Android ゲーム コントローラのハプティクス設定は、ゲーム デベロッパーの創造性を広げるだけでなく、プレーヤーにこれまで以上にリアルなゲーム エクスペリエンスを提供します。

Kotlin

fun triggerVibrationMultiChannel(
  deviceId: Int, leftIntensity: Int, leftDuration: Int,
  rightIntensity: Int, rightDuration: Int) {
  val inputDevice = InputDevice.getDevice(deviceId)
  val vibratorManager = inputDevice!!.vibratorManager
  if (vibratorManager != null) {
    val vibratorIds = vibratorManager.vibratorIds
    val vibratorCount = vibratorIds.size
    if (vibratorCount > 0) {
      // We have an assumption that game controllers have two vibrators
      // corresponding to a left motor and a right motor, and the left
      // motor will be first.
      updateVibrator(vibratorManager.getVibrator(vibratorIds  [0]), leftIntensity, leftDuration)
      if (vibratorCount > 1) {
        updateVibrator(vibratorManager.getVibrator(vibratorIds[1]), rightIntensity, rightDuration)
      }
    }
  }
}

fun updateVibrator(vibrator: Vibrator?, intensity: Int, duration: Int) {
  if (vibrator != null) {
    if (intensity == 0) {
      vibrator.cancel()
    } else if (duration > 0) {
      vibrator.vibrate(VibrationEffect.createOneShot(duration.toLong(), intensity))
    }
  }
}

Java

public void triggerVibrationMultiChannel(
    int deviceId, int leftIntensity, int leftDuration,
    int rightIntensity, int rightDuration) {

    InputDevice inputDevice = InputDevice.getDevice(deviceId);

    // Check if device exists to avoid NullPointerException
    if (inputDevice == null) {
      return;
    }

    VibratorManager vibratorManager = inputDevice.getVibratorManager();
    if (vibratorManager != null) {
        int[] vibratorIds = vibratorManager.getVibratorIds();
        int vibratorCount = vibratorIds.length;

        if (vibratorCount > 0) {
            // We have an assumption that game controllers have two vibrators
            // corresponding to a left motor and a right motor, and the left
            // motor will be first.
            updateVibrator(vibratorManager.getVibrator(vibratorIds[0]), leftIntensity, leftDuration);

            if (vibratorCount > 1) {
                updateVibrator(vibratorManager.getVibrator(vibratorIds[1]), rightIntensity, rightDuration);
            }
        }
    }
}

public void updateVibrator(Vibrator vibrator, int intensity, int duration) {
    if (vibrator != null) {
        if (intensity == 0) {
            vibrator.cancel();
        } else if (duration > 0) {
            vibrator.vibrate(VibrationEffect.createOneShot. ((long) duration, intensity));
        }
    }
}

バイブレーションを使用するには、機能と権限を設定します。

<manifest ...>
  ...
  <uses-permission android:name="android.permission.VIBRATE"/>
  ...
</manifest>

VibratorManager と アプリ マニフェストの詳細については、こちらをご覧ください。

モーション センサー

ゲームプレイ エクスペリエンスを向上させる最も革新的なテクノロジーの 1 つに、モーション センサーを搭載した Android ゲーム コントローラがあります。このテクノロジーは、ユーザーの物理的な動きを正確に検出し、そのデータをゲーム内のアクションに変換することで、より直感的で没入感のあるゲーム エクスペリエンスを提供します。 この概要では、Android ゲーム コントローラのモーション センサー機能の仕組みについて説明します。

モーション センサーには通常、ジャイロスコープと加速度計が組み込まれており、ユーザーの動きと向きを検出します。

加速度リスナー クラスとジャイロスコープ リスナー クラスを実装し、これらのリスナーをコントローラのセンサー マネージャーに登録する必要があります。

Kotlin

fun setIntegratedAccelerometerActive(deviceId: Int) {
  val device = InputDevice.getDevice(deviceId)
  val sensorManager = device?.sensorManager
  val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
  if (accelerometer != null) {
    val accelerometerListener =
      GameControllerAccelerometerListener(accelerometer)
    sensorManager.registerListener(
      accelerometerListener, accelerometer,
      SensorManager.SENSOR_DELAY_GAME
    )
  }
}

fun setIntegratedGyroscopeActive(deviceId: Int) {
  val device = InputDevice.getDevice(deviceId)
  val sensorManager = device?.sensorManager
  val gyroscope = sensorManager?.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
  if (gyroscope != null) {
    val gyroscopeListener = GameControllerGyroscopeListener(gyroscope)
    sensorManager.registerListener(
      gyroscopeListener, gyroscope,
      SensorManager.SENSOR_DELAY_GAME
    )
  }
}

class GameControllerAccelerometerListener(private val listenerAccelerometer: Sensor?) :
  SensorEventListener {
  override fun onSensorChanged(event: SensorEvent) {
    if (listenerAccelerometer != null) {
      synchronized(listenerAccelerometer) {
        if (event.sensor == listenerAccelerometer) {
          Log.d("Accelerometer",
            "onSensorChanged " + event.values[0] + ", "
            + event.values[1] + ", " + event.values[2])
        }
      }
    }
  }

  override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
  }
}

class GameControllerGyroscopeListener(private val listenerGyroscope: Sensor?) :
  SensorEventListener {
  override fun onSensorChanged(event: SensorEvent) {
    if (listenerGyroscope != null) {
      synchronized(listenerGyroscope) {
        if (event.sensor == listenerGyroscope) {
          Log.d("Gyroscope",
            "onSensorChanged " + event.values[0] + ", " +
            event.values[1] + ", " + event.values[2])
        }
      }
    }
 }

  override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
  }
}

Java


public void setIntegratedAccelerometerActive(int deviceId) {
    InputDevice device = InputDevice.getDevice(deviceId);
    // Safe handling for null device or sensor manager
    if (device == null) {
      return;
    }
    SensorManager sensorManager = device.getSensorManager();
    if (sensorManager == null) {
      return;
    }

    Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    if (accelerometer != null) {
      GameControllerAccelerometerListener   accelerometerListener =
          new GameControllerAccelerometerListener(accelerometer);
        sensorManager.registerListener(
          accelerometerListener, accelerometer,
          SensorManager.SENSOR_DELAY_GAME
        );
    }
}

public void setIntegratedGyroscopeActive(int deviceId) {
    InputDevice device = InputDevice.getDevice(deviceId);
    if (device == null) {
        return;
    }
    SensorManager sensorManager = device.getSensorManager();
    if (sensorManager == null) {
        return;
    }
    Sensor gyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
    if (gyroscope != null) {
        GameControllerGyroscopeListener gyroscopeListener =
          new GameControllerGyroscopeListener(gyroscope);
        sensorManager.registerListener(
          gyroscopeListener, gyroscope,
          SensorManager.SENSOR_DELAY_GAME
        );
    }
}

public static class GameControllerAccelerometerListener implements SensorEventListener {
    private final Sensor listenerAccelerometer;
    public GameControllerAccelerometerListener(Sensor   listenerAccelerometer) {
        this.listenerAccelerometer = listenerAccelerometer;
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (listenerAccelerometer != null) {
            synchronized (listenerAccelerometer) {
                if (event.sensor == listenerAccelerometer) {
                    Log.d("Accelerometer",
                      "onSensorChanged " + event.values[0] + ", "
                      + event.values[1] + ", " + event.values[2]);
                }
            }
        }
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
}

public static class GameControllerGyroscopeListener implements SensorEventListener {
    private final Sensor listenerGyroscope;

    public GameControllerGyroscopeListener(Sensor listenerGyroscope) {
        this.listenerGyroscope = listenerGyroscope;
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (listenerGyroscope != null) {
            synchronized (listenerGyroscope) {
                if (event.sensor == listenerGyroscope) {
                    Log.d("Gyroscope",
                      "onSensorChanged " + event.values[0] +  ", " +
                        event.values[1] + ", " + event.values  [2]);
                }
            }
        }
    }
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
}

モーション センサーと SensorEventListenerの詳細については、こちらをご覧ください。

ライト

Android ゲーム コントローラのライトの色設定により、視覚的な要素を通じてゲームプレイに新たな没入感が加わります。

ライトの色機能では、コントローラに内蔵された LED ライトを使用してさまざまな色を表示します。これらの色は、さまざまなゲーム シナリオに応じて動的に変化します。 たとえば、プレーヤーの体力が危険な状態になるとライトが赤く点滅したり、特定のミッションを完了すると緑色に点灯したりして、ゲーム内イベントに基づいて視覚的なフィードバックを提供します。これらのライトの色設定により、ユーザー エンゲージメントが深まり、ゲームのサスペンスと楽しさが向上し、プレーヤーはゲームの世界にさらに没入できます。

Android ゲーム コントローラのライトの色機能は、単なる装飾以上の役割を果たします。ゲームの雰囲気を設定し、ユーザー エクスペリエンスを向上させるうえで重要な役割を果たします。

Kotin

fun changeControllerLightColor(deviceId: Int, color: Int) {
  val device = InputDevice.getDevice(deviceId)
  device?.let {
    if (it.sources and InputDevice.SOURCE_JOYSTICK == InputDevice.SOURCE_JOYSTICK) {
      val lightsManager = device.lightsManager
      lightsManager?.let { manager ->
        manager.lights.forEach { light ->
          val stateBuilder = LightState.Builder()
          stateBuilder.setColor(color)
          val requestBuilder = LightsRequest.Builder()
          requestBuilder.addLight(light, stateBuilder.build())
          val lightsSession = lightsManager.openSession()
          lightsSession.requestLights(requestBuilder.build())
        }
      }
    }
  }
}

Java

public void changeControllerLightColor(int deviceId, int  color) {
    InputDevice device = InputDevice.getDevice(deviceId);

    if (device != null) {
      // Check if the device is a joystick.
      // Note: Parentheses are required around the bitwise AND operation in Java
      // because == has higher precedence than &.
        if ((device.getSources() & InputDevice.  SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK) {
            LightsManager lightsManager = device.getLightsManager();

            if (lightsManager != null) {
                for (Light light : lightsManager.getLights()) {
                    LightState.Builder stateBuilder = new   LightState.Builder();
                    stateBuilder.setColor(color);

                    LightsRequest.Builder requestBuilder = new LightsRequest.Builder();
                    requestBuilder.addLight(light, stateBuilder.build());

                    LightsManager.Session lightsSession =   lightsManager.openSession();
                    lightsSession.requestLights(requestBuilder.build());
                }
            }
        }
    }
}

コントローラのライトを使用するには、マニフェストでゲームパッド機能と LIGHTS 権限を宣言します。

<manifest ...>
  ...
  <uses-permission android:name="android.permission.LIGHTS" />
  ...
</manifest>

LightsManager と アプリ マニフェストの詳細については、こちらをご覧ください。

コントローラのタッチパッド

一部のゲーム コントローラにはタッチパッドが搭載されており、ナビゲーション メニューの操作やゲーム キャラクターの操作など、さまざまなゲーム内アクションに直感的に使用できます。

ゲーム コントローラのタッチパッド
図 1.ゲーム コントローラのタッチパッド。

タッチパッドが統合されたゲーム コントローラを使用すると、Android でデバイスを直接操作できます。タッチパッドに触れると、画面上にマウスポインタが表示され、マウスのような直感的な操作が可能になります。