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

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

لمسی

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

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

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

کاتلین

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

برای استفاده از ویبره، یک ویژگی و مجوز تنظیم می‌کند.

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

برای اطلاعات بیشتر در مورد VibratorManager و App manifest .

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

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

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

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

کاتلین

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 .

چراغ‌ها

تنظیمات رنگ نور در دسته‌های بازی اندروید، از طریق عناصر بصری، بُعد جدیدی از غوطه‌وری را به گیم‌پلی اضافه می‌کند.

ویژگی رنگ نور از چراغ‌های LED داخلی در کنترلر برای نمایش رنگ‌های مختلف استفاده می‌کند که به صورت پویا به سناریوهای مختلف بازی پاسخ می‌دهند. به عنوان مثال، چراغ‌ها ممکن است وقتی سلامتی بازیکن بحرانی است قرمز چشمک بزنند یا پس از اتمام یک ماموریت خاص سبز شوند و بازخورد بصری را بر اساس رویدادهای درون بازی ارائه دهند. این تنظیمات رنگ نور، تعامل کاربر را عمیق‌تر می‌کند، تعلیق و لذت بازی را افزایش می‌دهد و به بازیکنان کمک می‌کند تا به طور کامل‌تری در دنیای بازی غرق شوند.

ویژگی‌های رنگ نور در دسته‌های بازی اندروید چیزی بیش از یک هدف تزئینی صرف است - این ویژگی نقش مهمی در تنظیم حال و هوای بازی و بهبود تجربه کاربری دارد.

کوتین

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

برای استفاده از ویبره، یک ویژگی و مجوز تنظیم می‌کند.

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

برای اطلاعات بیشتر در مورد LightsManager و App manifest .

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

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

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

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