ویژگی‌های اضافی کنترل‌کننده

کنترل‌کننده‌های بازی به ویژگی‌های اضافه‌ای مجهز هستند که تعامل و غوطه‌وری بازیکن را به‌طور قابل‌توجهی بهبود می‌بخشند. عملکردهای لمسی، حسگرهای حرکتی، و نور کنترلرهای بازی Android به‌ویژه در عمیق‌تر و غنی‌تر کردن تجربه بازی نقش مهمی دارند. هر ویژگی به‌طور منحصربه‌فردی حواس بازیکن را تحریک می‌کند و تعاملات معنادارتر و شهودی‌تری را در بازی ایجاد می‌کند.

برای اعلام اینکه برنامه‌تان از کنترل‌کننده‌های بازی پشتیبانی می‌کند، ویژگی android.hardware.gamepad را به مانیفست برنامه‌تان اضافه کنید:

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

فناوری لمسی

ویژگی لمسی در کنترلرهای بازی Android فناوری مهمی است که بازخورد لمسی واقع‌گرایانه‌ای درطول بازی ارائه می‌دهد.

فناوری لمسی ازطریق لرزش یا حرکت، احساسات فیزیکی را به کاربر منتقل می‌کند. برای مثال، وقتی انفجاری در بازی رخ می‌دهد، کنترل‌کننده می‌لرزد و به بازیکن امکان می‌دهد تأثیر آن را به‌صورت واقعی احساس کند. علاوه‌براین، لرزش‌های ظریف می‌تواند با صدای راه رفتن یا دویدن شخصیت هماهنگ شود و تجربه‌ای واقعی‌تر ارائه دهد. این نوع بازخورد لمسی به بازیکنان امکان می‌دهد رویدادهای مختلفی را که در بازی اتفاق می‌افتد به‌صورت فیزیکی احساس کنند.

این فناوری غوطه‌وری بازیکن را به حداکثر می‌رساند، پاسخ‌های احساسی را تقویت می‌کند، و پویایی بازی را غنی‌تر می‌کند. تنظیمات لمسی در کنترل‌کننده‌های بازی Android نه تنها امکانات خلاقانه را برای توسعه‌دهندگان بازی گسترش می‌دهد، بلکه تجربه بازی واقعی‌تری را نسبت‌به قبل برای بازیکنان فراهم می‌کند.

کاتلین

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

جاوا

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 و مانیفست برنامه.

حسگرهای حرکتی

یکی از نوآورانه‌ترین فناوری‌هایی که تجربه بازی را بهبود می‌بخشد، کنترل‌کننده بازی Android مجهز به حسگر حرکتی است. این فناوری حرکات فیزیکی کاربران را به‌طور دقیق تشخیص می‌دهد و آن داده‌ها را به کنش‌هایی در بازی تبدیل می‌کند و تجربه بازی کردن شهودی‌تر و همه‌جانبه‌تری ارائه می‌دهد. در این مقدمه، نحوه عملکرد ویژگی‌های حسگر حرکتی در کنترل‌کننده‌های بازی Android را بررسی خواهیم کرد.

حسگرهای حرکتی معمولاً ژیروسکوپ و شتاب‌سنج را برای تشخیص حرکات و جهت‌گیری‌های کاربران ترکیب می‌کنند.

این برنامه باید کلاس‌های شنونده شتاب و ژیروسکوپ را پیاده‌سازی کند و این شنونده‌ها را در مدیر حسگر کنترل‌کننده ثبت کند.

کاتلین

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

جاوا


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

جاوا

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 و مانیفست برنامه.

صفحه لمسی کنترل‌کننده

برخی‌از کنترل‌کننده‌های بازی دارای صفحه لمسی هستند که می‌توان از آن برای انواع کنش‌های درون‌بازی استفاده کرد، مثلاً پیمایش منوها یا کنترل کردن شخصیت‌های بازی به‌صورت شهودی‌تر.

صفحه لمسی روی کنترل‌کننده بازی
شکل ۱. صفحه لمسی روی کنترل‌کننده بازی.

کنترل‌کننده‌های بازی با پد لمسی یکپارچه کنترل مستقیم دستگاه را در Android ارائه می‌دهند. لمس کردن صفحه لمسی باعث ایجاد اشاره‌گر موشواره روی صفحه می‌شود و امکان پیمایش بصری شبیه موشواره را فراهم می‌کند.