Zusätzliche Controller-Funktionen

Gamecontroller sind mit zusätzlichen Funktionen ausgestattet, die die Interaktion und das Eintauchen in die Spielwelt deutlich verbessern. Die Haptik, Bewegungssensoren und Lichtfunktionen von Android-Gamecontrollern tragen besonders dazu bei, das Spielerlebnis zu intensivieren und zu bereichern. Jede Funktion stimuliert die Sinne des Spielers auf einzigartige Weise und ermöglicht so sinnvollere und intuitivere Interaktionen im Spiel.

Haptik

Die Haptikfunktion in Android-Controllern ist eine wichtige Technologie, die während des Spiels für realistisches taktiles Feedback sorgt.

Haptische Technologie vermittelt dem Nutzer durch Vibrationen oder Bewegungen physische Empfindungen. Wenn im Spiel beispielsweise eine Explosion stattfindet, vibriert der Controller, sodass der Spieler den Aufprall realistisch spüren kann. Außerdem können subtile Vibrationen mit dem Geräusch eines Charakters synchronisiert werden, der geht oder rennt, um ein noch realistischeres Erlebnis zu bieten. Durch diese Art von haptischem Feedback können Spieler verschiedene Ereignisse im Spiel physisch spüren.

Diese Technologie maximiert das Eintauchen der Spieler in die Spielwelt, verstärkt emotionale Reaktionen und bereichert die Dynamik des Spiels. Die Haptik-Einstellungen in Android-Gamecontrollern erweitern nicht nur die kreativen Möglichkeiten für Spieleentwickler, sondern bieten Spielern auch ein realistischeres Spielerlebnis als je zuvor.

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

Für die Vibrationsfunktion werden ein Feature und eine Berechtigung festgelegt.

<application ...>
  ...
  <uses-feature android:name="android.hardware.gamepad" android:required="true"/>
  <uses-permission android:name="android.permission.VIBRATE"/>
  ...
</application>

Weitere Informationen zu VibratorManager

Bewegungssensoren

Eine der innovativsten Technologien, die das Spielerlebnis verbessern, ist der Android-Controller mit Bewegungssensor. Diese Technologie erkennt die physischen Bewegungen von Nutzern präzise und setzt diese Daten in Aktionen im Spiel um. So wird ein intuitiveres und intensiveres Spielerlebnis ermöglicht. In dieser Einführung erfahren Sie, wie die Bewegungssensorfunktionen in Android-Gamecontrollern funktionieren.

Bewegungssensoren enthalten in der Regel Gyroskope und Beschleunigungsmesser, um die Bewegungen und Ausrichtungen von Nutzern zu erkennen.

Dazu müssen Beschleunigungs- und Gyroskop-Listener-Klassen implementiert und diese Listener beim Sensormanager des Controllers registriert werden.

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

Weitere Informationen zu Bewegungssensoren und SensorEventListener

Lichter

Die Einstellungen für die Lichtfarbe auf Android-Gamecontrollern sorgen durch visuelle Elemente für eine neue Dimension des Eintauchens in das Gameplay.

Bei der Funktion „Lichtfarbe“ werden die im Controller integrierten LEDs verwendet, um verschiedene Farben anzuzeigen, die dynamisch auf unterschiedliche Spielszenarien reagieren. Die Beleuchtung kann beispielsweise rot blinken, wenn die Gesundheit des Spielers kritisch ist, oder grün leuchten, wenn eine bestimmte Mission abgeschlossen wurde. So wird visuelles Feedback basierend auf In-Game-Ereignissen gegeben. Diese Einstellungen für die Lichtfarbe steigern das Nutzer-Engagement, erhöhen die Spannung und den Spaß am Spiel und helfen den Spielern, tiefer in die Spielwelt einzutauchen.

Die Lichtfarbenfunktionen in Android-Gamecontrollern dienen nicht nur dekorativen Zwecken, sondern spielen eine wichtige Rolle bei der Stimmung des Spiels und der Verbesserung der Nutzerfreundlichkeit.

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

Für die Vibrationsfunktion werden ein Feature und eine Berechtigung festgelegt.

<application ...>
  ...
  <uses-feature android:name="android.hardware.gamepad" android:required="true"/>
  <uses-permission android:name="android.permission.LIGHTS" />
  ...
</application>

Weitere Informationen zu LightsManager

Touchpad des Controllers

Einige Gamecontroller haben ein Touchpad, das für verschiedene In-Game-Aktionen verwendet werden kann, z. B. zum Navigieren in Menüs oder zum intuitiveren Steuern von Spielfiguren.

Touchpad auf dem Controller
Abbildung 1: Touchpad auf dem Controller

Gamecontroller mit integrierten Touchpads ermöglichen die direkte Gerätesteuerung auf Android-Geräten. Durch Berühren des Touchpads wird ein Mauszeiger auf dem Bildschirm angezeigt, der eine intuitive mausähnliche Navigation ermöglicht.