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

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.

主站蜘蛛池模板: 静宁县| 铜川市| 永昌县| 石泉县| 夏邑县| 永州市| 德阳市| 沅江市| 南漳县| 湖口县| 奉贤区| 泉州市| 郑州市| 大兴区| 无极县| 平南县| 黄浦区| 肃南| 兰州市| 灵台县| 佛山市| 瑞金市| 正定县| 日照市| 河津市| 邻水| 景东| 广昌县| 曲阳县| 冷水江市| 象山县| 信丰县| 四川省| 彭阳县| 都匀市| 黄龙县| 新建县| 红河县| 贵阳市| 平乡县| 顺平县|