官术网_书友最值得收藏!

Sensors and InputControllers

Sensors are a common way to control games on smartphones. They work fine when the only controls in the game are left and right (like a car racing game). If you plan to also move up and down, you need to ask the player to do a calibration at the beginning of the game to make it usable. Note that, when you are using only one axis, such calibration is not necessary.

In addition to this, the up and down movement tends to interfere with the sensorLandscape orientation. So, the use of sensors is not a very good idea for YASS.

Note

Sensors are good controls only in certain cases.

You also have to consider that, while sensors are a replacement for directions, you still need to place the action buttons on the screen—in our case, the fire button.

We are not going to use sensors for YASS but, if you want to make a game that uses them, we will cover the basics.

You need to register a listener for the accelerometer and another one for the magnetic field. You should only listen to the sensors while the game is running, so we will override the life cycle methods to register and unregister sensors accordingly:

private void registerListeners() {
  SensorManager sm = (SensorManager)
    mActivity.getSystemService(Activity.SENSOR_SERVICE);
  sm.registerListener(mAccelerometerChangesListener,
    sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
    SensorManager.SENSOR_DELAY_FASTEST);
  sm.registerListener(mMagneticChangesListener,
    sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
    SensorManager.SENSOR_DELAY_FASTEST);
}

private void unregisterListeners() {
  SensorManager sm = (SensorManager)
    mActivity.getSystemService(Activity.SENSOR_SERVICE);
  sm.unregisterListener(mAccelerometerChangesListener);
  sm.unregisterListener(mMagneticChangesListener);
}

@Override
public void onStart() {
  registerListeners();
}
@Override
public void onStop() {
  unregisterListeners();
}
@Override
public void onResume() {
  registerListeners();
}
@Override
public void onPause() {
  unregisterListeners();
}

Note that we are using SensorManager.SENSOR_DELAY_FASTEST, which means that the sensors will give feedback as fast and as often as they can. This is very important for real-time games.

We are setting objects as listeners. Each listener will just copy the values of the sensor into a local array that we will process later on. For example, in the case of an accelerometer, we will do:

@Override
public void onSensorChanged(SensorEvent event) {
  System.arraycopy(event.values, 0, mLastAccels, 0, 3);
}

To obtain the final value, we have to do some calculations. So, we will add a onPreUpdate method that will be called by the GameEngine just before calling onUpdate.

It is important to note that there are some special cases. They are as follows:

  • There are devices that lack a magnetic field sensor. In such cases, we can use a simplified version using the value of the accelerometer. Nvidia Shield and specific versions of Nook are some of these devices.
  • In all cases, the sensors are related to the default orientation of the device, which can be either landscape or portrait. We have to take this into consideration while processing the values.

All in all, the conversion for the horizontal axis can be done like this:

private double getHorizontalAxis() {
  if (SensorManager.getRotationMatrix(mRotationMatrix, null, mLastAccels, mLastMagFields)) {
    if (mRotation == Surface.ROTATION_0) {
      SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, mRotationMatrix);
      SensorManager.getOrientation(mRotationMatrix, mOrientation);
      return mOrientation[1] * DEGREES_PER_RADIAN;
    }
    else {
      SensorManager.getOrientation(mRotationMatrix, mOrientation);
      return -mOrientation[1] * DEGREES_PER_RADIAN;
    }
  }
  else {
    // Case for devices which do NOT have magnetic sensors
    if (mRotation == Surface.ROTATION_0) {
      return -mLastAccels[0]* 5;
    }
    else {
      return -mLastAccels[1] * -5;
    }
  }
}

The getHorizontalAxis code does the following steps:

  • Calculates the rotation matrix using the last data from the accelerometer and the magnetic sensor.
  • If it returns true, all goes well. Based on the rotation of the device, we decide whether we need to remap the coordinate system or not and then return the orientation that is converted into degrees.
  • If it could not be calculated (lack of a magnetic field sensor), the method returns false. We have to rely on an approximation using the accelerometer values. Based on the rotation of the device, we should use one or another axis.

The rotation of the device can be read in the constructor of the InputController with a single line of code.

mRotation = yassActivity.getWindowManager().getDefaultDisplay().getRotation();

Finally, the onPreUpdate method:

@Override
public void onPreUpdate() {
  mHorizontalFactor = getHorizontalAxis()/ MAX_ANGLE;
  if (mHorizontalFactor > 1) {
    mHorizontalFactor = 1;
  }
  else if (mHorizontalFactor < -1) {
    mHorizontalFactor = -1;
  }
  mVerticalFactor = 0;
}

The is method just converts the reading (in degrees) into values in the range [-1,1] by using the maximum angle at which we consider it to be fully tilted. I recommend you to play with this constant and start with 30 degrees.

For more information on handling sensors, you can check the official documentation http://developer.android.com/guide/topics/sensors/sensors_overview.html.

主站蜘蛛池模板: 吉首市| 商城县| 洪湖市| 怀远县| 伊宁市| 武平县| 天峻县| 安平县| 岳西县| 巴塘县| 清徐县| 盐亭县| 丽江市| 彭阳县| 子洲县| 夏河县| 霍林郭勒市| 登封市| 吴堡县| 道孚县| 临沧市| 剑阁县| 武鸣县| 襄城县| 洞头县| 虹口区| 嘉善县| 乐昌市| 漯河市| 彭水| 江安县| 民权县| 磐石市| 天祝| 茶陵县| 仙游县| 特克斯县| 蒙自县| 阿勒泰市| 东至县| 甘洛县|