Fonctionnalités supplémentaires de la manette

Les manettes de jeu sont équipées de fonctionnalités supplémentaires qui améliorent considérablement l'interaction et l'immersion des joueurs. Les fonctionnalités tactiles, les capteurs de mouvement et les lumières des manettes de jeu Android contribuent particulièrement à approfondir et à enrichir l'expérience de jeu. Chaque fonctionnalité stimule les sens du joueur de manière unique, favorisant des interactions plus significatives et intuitives dans le jeu.

Pour déclarer que votre application est compatible avec les manettes de jeu, ajoutez la fonctionnalité android.hardware.gamepad à votre fichier manifeste :

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

Technologie tactile

La fonctionnalité tactile des manettes de jeu Android est une technologie essentielle qui fournit un retour tactile réaliste pendant le jeu.

La technologie tactile transmet des sensations physiques à l'utilisateur par le biais de vibrations ou de mouvements. Par exemple, lorsqu'une explosion se produit dans le jeu, la manette vibre, ce qui permet au joueur de ressentir l'impact de manière réaliste. De plus, des vibrations subtiles peuvent être synchronisées avec le son d'un personnage qui marche ou court, offrant ainsi une expérience plus réaliste. Ce type de retour tactile permet aux joueurs de ressentir physiquement différents événements qui se produisent dans le jeu.

Cette technologie maximise l'immersion du joueur, amplifie les réponses émotionnelles et enrichit la dynamique du jeu. Les paramètres tactiles des manettes de jeu Android élargissent non seulement les possibilités créatives des développeurs de jeux, mais offrent également aux joueurs une expérience de jeu plus réaliste que jamais.

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));
        }
    }
}

Pour utiliser la vibration, définissez une fonctionnalité et une autorisation.

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

Pour en savoir plus sur VibratorManager et le fichier manifeste d'application.

Capteurs de mouvement

L'une des technologies les plus innovantes qui améliorent l'expérience de jeu est la manette de jeu Android équipée d'un capteur de mouvement. Cette technologie détecte précisément les mouvements physiques des utilisateurs et traduit ces données en actions dans le jeu, offrant ainsi une expérience de jeu plus intuitive et immersive. Dans cette introduction, nous allons voir comment fonctionnent les fonctionnalités de capteur de mouvement des manettes de jeu Android.

Les capteurs de mouvement intègrent généralement des gyroscopes et des accéléromètres pour détecter les mouvements et les orientations des utilisateurs.

Il doit implémenter des classes d'écouteur d'accélération et de gyroscope, et enregistrer ces écouteurs auprès du gestionnaire de capteurs de la manette.

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) {
    }
}

Pour en savoir plus sur les capteurs de mouvement et SensorEventListener.

Lumières

Les paramètres de couleur des lumières des manettes de jeu Android ajoutent une nouvelle dimension d'immersion au gameplay grâce à des éléments visuels.

La fonctionnalité de couleur des lumières utilise des voyants LED intégrés à la manette pour afficher différentes couleurs, qui répondent de manière dynamique à différents scénarios de jeu. Par exemple, les lumières peuvent clignoter en rouge lorsque la santé du joueur est critique ou s'allumer en vert une fois une mission spécifique terminée, fournissant ainsi un retour visuel basé sur les événements du jeu. Ces paramètres de couleur des lumières renforcent l'engagement utilisateur, augmentent le suspense et le plaisir du jeu, et aident les joueurs à s'immerger plus pleinement dans le monde du jeu.

Les fonctionnalités de couleur des lumières des manettes de jeu Android ne sont pas qu'un simple élément décoratif : elles jouent un rôle important dans la définition de l'ambiance du jeu et l'amélioration de l'expérience utilisateur.

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());
                }
            }
        }
    }
}

Pour utiliser les lumières de la manette, déclarez la fonctionnalité de manette de jeu et l'autorisation LIGHTS dans votre fichier manifeste :

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

Pour en savoir plus sur LightsManager et le fichier manifeste d'application.

Touchpad de la manette

Certaines manettes de jeu incluent un touchpad qui peut être utilisé pour diverses actions dans le jeu, comme naviguer dans les menus ou contrôler les personnages de manière plus intuitive.

Pavé tactile de la manette de jeu
Figure 1. Touchpad sur la manette de jeu.

Les manettes de jeu avec touchpad intégré offrent un contrôle direct de l'appareil sur Android. Lorsque vous touchez le pavé tactile, un pointeur de la souris s'affiche à l'écran, ce qui permet une navigation intuitive de type souris.