تتضمّن أذرع التحكّم في الألعاب ميزات إضافية تعزّز بشكلٍ كبير تفاعل اللاعبين وتجربتهم الغامرة. تساهم تقنية اللمس ومستشعرات الحركة ووظائف الإضاءة في أذرع التحكّم في ألعاب Android بشكلٍ خاص في تعميق تجربة اللعب وإثرائها. تحفّز كل ميزة حواس اللاعب بشكلٍ فريد، ما يعزّز التفاعلات الأكثر أهمية وبديهية داخل اللعبة.
تقنية اللمس
تُعدّ ميزة اللمس في أذرع التحكّم في ألعاب 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));
}
}
}
لاستخدام الاهتزاز، يتم ضبط ميزة وإذن.
<application ...>
...
<uses-feature android:name="android.hardware.gamepad" android:required="true"/>
<uses-permission android:name="android.permission.VIBRATE"/>
...
</application>
لمزيد من المعلومات عن
VibratorManager و
بيان التطبيق.
مستشعرات الحركة
من بين التقنيات الأكثر ابتكارًا التي تعزّز تجارب اللعب، ذراع التحكّم في ألعاب 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());
}
}
}
}
}
لاستخدام الاهتزاز، يتم ضبط ميزة وإذن.
<application ...>
...
<uses-feature android:name="android.hardware.gamepad" android:required="true"/>
<uses-permission android:name="android.permission.LIGHTS" />
...
</application>
لمزيد من المعلومات عن
LightsManager وبيان التطبيق
.
لوحة اللمس في ذراع التحكّم
تتضمّن بعض أذرع التحكّم في الألعاب لوحة لمس يمكن استخدامها لتنفيذ مجموعة متنوعة من الإجراءات داخل اللعبة، مثل التنقّل في القوائم أو التحكّم في شخصيات اللعبة بطريقة أكثر بديهية.
توفّر أذرع التحكّم في الألعاب التي تتضمّن لوحات لمس مدمجة تحكّمًا مباشرًا في الجهاز على Android. يؤدي لمس لوحة اللمس إلى إنشاء مؤشر ماوس على الشاشة، ما يسمح بالتنقل البديهي الذي يشبه الماوس.