Android游戏编程之加快计和罗盘测试
游戏中一个有趣的输入方法是加速计,所有的Android设备都要求有一个3D加速计。同样的还有罗盘功能能感应磁场方向以及手机俯仰角。
为了获取加速计信息,我们注册一个侦听器,需要实现的接口名为SensorEventListener,它具有两个方法:
public void onSensorChanged(SensorEvent event);
public void onAccuracyChanged(Sensor sensor, int accuracy);
当一个新的加速计事件发生时会调用第一个方法,而当加速计的精度发生变化时会调用第二个方法。一般我们可以放心的忽略第二个方法。
为了实现这个功能,首先我们需要确认设备上是否具有一个加速计。尽管现在所有的Android设备都应该有一个加速计,但也许将来会有变化。我们必须百分之百确保该输入方法是可用的。
首先我们需要做的是获得一个SensorManager实例,它将会表明设备是否安装了加速计,以及在哪里注册侦听器。我们可以通过Context接口的一个方法来获取SensorManager实例:
SensorManager manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
SensorManager是Android系统提供的一个系统服务,Android具有多个系统服务,每一个服务可向我们提供不同的系统信息。
一旦获取SensorManager实例,就能检查加速计是否可用:
boolean hasAccel = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() > 0;
通过这段代码,我们查询管理器以了解所有安装的accelerometer类型加速计。这就意味着一个设备可具有多个加速计,不过,实际上只返回一个加速计传感器。
如果已经安装了一个加速计,我们可通过SensorManager来获取它并向其注册SensorEventListener,如下所示:
Sensor sensor = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0);
boolean sucess = manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);
参数SensorManager.SENSOR_DELAY_GAME用于指定侦听器更新的频率,其更新内容来自加速计的最新状态。
SensorManager.registerListener()方法返回一个Boolean变量,以表明注册过程是否成功。为了确保任何传感器事件,我们需要价差该Boolean变量。
一旦成功注册侦听器,我们就可以通过SensorEventListener.onSensorChanged()方法来接收SensorEvent。该方法只有在传感器的状态发生变化时才会被调用。
现在该处理SensorEvent了。该SensorEvent有一个公有浮点型数组成员变量SensorEvent.values,它存储了加速计当前3个轴的加速度值。SensorEvent.values[0]保存X轴的值,SensorEvent.values[1]保存Y轴的值,SensorEvent.values[2]保存Z轴的值。
总体来说X、Y轴方向位于你的手机屏幕所在的平面,而Z轴垂直于手机屏幕所在平面,X轴一般位于手机短的那条边的方向,
其他的坐标轴大家可以充分发挥你的空间想象能力。
代码如下:
package org.example.ch04_android_basics; import android.app.Activity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.widget.TextView; public class AccelerometerTest extends Activity implements SensorEventListener{ TextView textView; StringBuilder builder = new StringBuilder(); @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); textView = new TextView(this); setContentView(textView); SensorManager manager = (SensorManager)getSystemService( Context.SENSOR_SERVICE); if(manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() == 0){ textView.setText("No accelerometer installed"); }else{ Sensor accelerometer = manager.getSensorList( Sensor.TYPE_ACCELEROMETER).get(0); if(!manager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME)){ textView.setText("Couldn't register sensor listener"); } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub } @Override public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub builder.setLength(0); builder.append("x: "); builder.append(event.values[0]); builder.append(", y: "); builder.append(event.values[1]); builder.append(", z: "); builder.append(event.values[2]); textView.setText(builder.toString()); } }
运行效果如图(我的手机是平放在桌面上的所以X,Y方向加速度几乎为0,Z轴大概是重力加速度9.8左右):
现在我们看看手机如何像一个飞机一样知道自己的俯仰角、翻转角和方向,方法和获取加速计信息差不多,就是获取的Sensor类型不同,在这里我们是:
Sensor compass = manager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
其余的都差不多,代码如下:
package org.example.ch04_android_basics; import android.app.Activity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.widget.TextView; public class OrientationTest extends Activity implements SensorEventListener{ TextView textView; StringBuilder builder = new StringBuilder(); float yaw; float pitch; float roll; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); textView = new TextView(this); setContentView(textView); SensorManager manager = (SensorManager)getSystemService( Context.SENSOR_SERVICE); if(manager.getSensorList(Sensor.TYPE_ORIENTATION).size() == 0){ textView.setText("No orientation installed"); }else{ Sensor compass = manager.getDefaultSensor( Sensor.TYPE_ORIENTATION); if(!manager.registerListener(this, compass, SensorManager.SENSOR_DELAY_GAME)){ textView.setText("Couldn't register sensor listener"); } } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // TODO Auto-generated method stub } @Override public void onSensorChanged(SensorEvent event) { // TODO Auto-generated method stub yaw = event.values[0]; pitch = event.values[1]; roll = event.values[2]; calculateOrientation(); } public void calculateOrientation(){ builder.setLength(0); builder.append("yaw: "); builder.append(yaw + "\n"); builder.append("pitch: " ); builder.append(pitch + "\n"); builder.append("roll: "); builder.append(roll); textView.setText(builder.toString()); } }
yaw存储的是偏航角即与地球磁场方向的偏角;范围在[0, 360]度之间
pitch存储的是手机的俯仰角; 范围在[-180, 180]度之间
roll存储的是手机的翻转角;范围在[-90, 90]度之间
现在我让手机平放在桌面上,指向正东方,会显示多少呢?运行效果如下: