- Mastering Android Game Development
- Raul Portales
- 750字
- 2021-07-16 13:59:10
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.
- 案例式C語言程序設計
- Debian 7:System Administration Best Practices
- Effective C#:改善C#代碼的50個有效方法(原書第3版)
- Visual Basic程序開發(學習筆記)
- 信息可視化的藝術:信息可視化在英國
- Visual Basic學習手冊
- 劍指Java:核心原理與應用實踐
- SQL Server實用教程(SQL Server 2008版)
- Julia for Data Science
- Clojure for Machine Learning
- 從零開始:UI圖標設計與制作(第3版)
- Getting Started with Python
- Python Digital Forensics Cookbook
- C語言程序設計實驗指導與習題精解
- Practical Time Series Analysis