Los controles de juegos están equipados con funciones adicionales que mejoran significativamente la interacción y la inmersión del jugador. Las funciones de tecnología háptica, sensores de movimiento y luces de los controles de juegos de Android son particularmente útiles para profundizar y enriquecer la experiencia de juego. Cada función estimula de forma única los sentidos del jugador, lo que fomenta interacciones más significativas e intuitivas dentro del juego.
Para declarar que tu app admite controles de juegos, agrega la función android.hardware.gamepad a tu manifiesto de la app:
<manifest ...>
...
<uses-feature android:name="android.hardware.gamepad" android:required="false"/>
...
</manifest>
Tecnología háptica
La función de tecnología háptica en los controles de juegos de Android es una tecnología crucial que proporciona comentarios táctiles realistas durante el juego.
La tecnología háptica transmite sensaciones físicas al usuario a través de vibraciones o movimientos. Por ejemplo, cuando se produce una explosión en el juego, el control vibra, lo que permite que el jugador sienta el impacto de forma realista. Además, las vibraciones sutiles se pueden sincronizar con el sonido de un personaje que camina o corre, lo que ofrece una experiencia más realista. Este tipo de respuesta táctil permite que los jugadores sientan físicamente varios eventos que ocurren dentro del juego.
Esta tecnología maximiza la inmersión del jugador, amplifica las respuestas emocionales y enriquece la dinámica del juego. La configuración de tecnología háptica en los controles de juegos de Android no solo amplía las posibilidades creativas para los desarrolladores de juegos, sino que también les brinda a los jugadores una experiencia de juego más realista que nunca.
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));
}
}
}
Para usar la vibración, se establece una función y un permiso.
<manifest ...>
...
<uses-permission android:name="android.permission.VIBRATE"/>
...
</manifest>
Para obtener más información sobre
VibratorManager y
el manifiesto de la app.
Sensores de movimiento
Una de las tecnologías más innovadoras que mejoran las experiencias de juego es el control de juegos de Android equipado con sensores de movimiento. Esta tecnología detecta con precisión los movimientos físicos de los usuarios y traduce esos datos en acciones dentro del juego, lo que proporciona una experiencia de juego más intuitiva y envolvente. En esta introducción, exploraremos cómo funcionan las funciones de sensores de movimiento en los controles de juegos de Android.
Por lo general, los sensores de movimiento incorporan giroscopios y acelerómetros para detectar los movimientos y las orientaciones de los usuarios.
Es necesario implementar clases de aceleración y de escucha de giroscopio, y registrar estos objetos de escucha con el administrador de sensores del control.
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) {
}
}
Para obtener más información sobre
los sensores de movimiento y
SensorEventListener.
Luces
La configuración de color de las luces en los controles de juegos de Android agrega una nueva dimensión de inmersión al juego a través de elementos visuales.
La función de color de las luces utiliza luces LED integradas en el control para mostrar varios colores, que responden de forma dinámica a diferentes situaciones de juego. Por ejemplo, las luces pueden parpadear en rojo cuando la salud del jugador es crítica o brillar en verde cuando se completa una misión específica, lo que proporciona comentarios visuales basados en eventos del juego. Esta configuración de color de las luces profundiza la interacción de los usuarios, aumenta el suspenso y el disfrute del juego, y ayuda a los jugadores a sumergirse por completo en el mundo del juego.
Las funciones de color de las luces en los controles de juegos de Android tienen más que un simple propósito decorativo: desempeñan un papel importante en la configuración del ambiente del juego y en la mejora de la experiencia del usuario.
Kotlin
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());
}
}
}
}
}
Para usar las luces del control, declara la función de control de juegos y el permiso LIGHTS en tu manifiesto:
<manifest ...>
...
<uses-permission android:name="android.permission.LIGHTS" />
...
</manifest>
Para obtener más información sobre
LightsManager y
el manifiesto de la app.
Panel táctil del control
Algunos controles de juegos incluyen un panel táctil que se puede usar para una variedad de acciones en el juego, como navegar por los menús o controlar los personajes del juego de una manera más intuitiva.
Los controles de juegos con paneles táctiles integrados ofrecen control directo del dispositivo en Android. Tocar el panel táctil genera un puntero del mouse en pantalla, lo que permite una navegación intuitiva similar a la del mouse.