传感器名称如下:
加速度传感器(accelerometer)
陀螺仪传感器(gyroscope)
环境光照传感器(light)
磁力传感器(magnetic field)
方向传感器(orientation)
压力传感器(pressure)
距离传感器(proximity)
温度传感器(temperature)
1 2 3 |
SensorManager mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE); |
2.实现SensorEventListener接口
说道SensorEventListener接口就不得不说SensorListener接口。在Android1.5一下是通过实现SensorListener接口来捕获 手机传感器状态,但是在1.5以上如果实现这个接口系统会提示你这行代码已经过期。今天我们不讨论SensorListener因为它已经是过时的东西了。主要讨论一下SensorEventListener接口。我们须要实现SensorEventListener这个接口 onSensorChanged(SensorEvent event)方法来捕获手机传感器的状态,拿到手机 X轴Y轴Z轴三个方向的重力分量,有了这三个方向的数据重力感应的原理我们就已经学会了,简单吧 哇咔咔~~
1 2 3 4 5 6 7 |
public void onSensorChanged(SensorEvent e) { float x = e.values[SensorManager.DATA_X]; float y = e.values[SensorManager.DATA_Y]; float z = e.values[SensorManager.DATA_Z]; } |
如图所示:上例代码中 float x y z 3个方向的取值范围是在 -10 到 10 之间,我向同学们说明一下 X轴 Y轴 Z轴 重力分量的含义。 这里须要注意的是坐标原点 向天空为正数 向地面为负数 刚好与编程时坐标是相反的。
手机屏幕向左侧方当X轴就朝向天空,垂直放置 这时候 Y 轴 与 Z轴没有重力分量,因为X轴朝向天空所以它的重力分量则最大 。这时候X轴 Y轴 Z轴的重力分量的值分别为(10,0,0)
手机屏幕向右侧方当X轴就朝向地面,垂直放置 这时候 Y 轴 与 Z轴没有重力分量,因为X轴朝向地面所以它的重力分量则最小 。这时候X轴 Y轴 Z轴的重力分量的值分别为(-10,0,0)
手机屏幕垂直竖立放置方当Y轴就朝向天空,垂直放置 这时候 X 轴 与 Z轴没有重力分量,因为Y轴朝向天空所以它的重力分量则最大 。这时候X轴 Y轴 Z轴的重力分量的值分别为(0,10,0)
手机屏幕垂直竖立放置方当Y轴就朝向地面,垂直放置 这时候 X 轴 与 Z轴没有重力分量,因为Y轴朝向地面所以它的重力分量则最小 。这时候X轴 Y轴 Z轴的重力分量的值分别为(0,-10,0)
手机屏幕向上当Z轴就朝向天空,水平放置 这时候 X 轴与Y轴没有重力分量,因为Z轴朝向天空所以它的重力分量则最大 。这时候X轴 Y轴 Z轴的重力分量的值分别为(0,0,10)
手机屏幕向上当Z轴就朝向地面,水平放置 这时候 X 轴与Y轴没有重力分量,因为Z轴朝向地面所以它的重力分量则最小 。这时候X轴 Y轴 Z轴的重力分量的值分别为(0,0,-10)
因为这张图片是在模拟器上截得,所以没有重力感应它的三个方向的的重力分量都为0。
3.注册SensorEventListener
使用SensorMannager调用getDefaultSensor(Sensor.TYPE_ACCELEROMETER)方法拿到加速重力感应的Sensor对象。因为本章我们讨论重力加速度传感器所以参数为Sensor.TYPE_ACCELEROMETER,如果须要拿到其它的传感器须要传入对应的名称。使用SensorMannager调用registerListener()方法来注册,第三个参数是检测的灵敏精确度根据不同的需求来选择精准度,游戏开发建议使用 SensorManager.SENSOR_DELAY_GAME。
1 2 3 4 5 6 7 8 9 10 |
mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE); mSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // 注册listener,第三个参数是检测的精确度 //SENSOR_DELAY_FASTEST 最灵敏 因为太快了没必要使用 //SENSOR_DELAY_GAME 游戏开发中使用 //SENSOR_DELAY_NORMAL 正常速度 //SENSOR_DELAY_UI 最慢的速度 mSensorMgr.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME); |
重力感应简单速度计算的方式。 每次摇晃手机计算出 X轴 Y轴 Z轴的重力分量可以将它们记录下来 然后每次摇晃的重力分量和之前的重力分量可以做一个对比 利用差值和时间就可以计算出他们的移动速度。(下面这段代码是我之前的博文中摘录过来的,因为那篇写的不是很好所以在这一篇中我详细总结一下)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
private SensorManager sensorMgr; Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); //保存上一次 x y z 的坐标 float bx = 0; float by = 0; float bz = 0; long btime = 0;//这一次的时间 sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE); SensorEventListener lsn = new SensorEventListener() { public void onSensorChanged(SensorEvent e) { float x = e.values[SensorManager.DATA_X]; float y = e.values[SensorManager.DATA_Y]; float z = e.values[SensorManager.DATA_Z]; //在这里我们可以计算出 X Y Z的数值 下面我们就可以根据这个数值来计算摇晃的速度了 //我想大家应该都知道计算速度的公事 速度 = 路程/时间 //X轴的速度 float speadX = (x - bx) / (System.currentTimeMillis() - btime); //y轴的速度 float speadY = (y - by) / (System.currentTimeMillis() - btime); //z轴的速度 float speadZ = (z - bz) / (System.currentTimeMillis() - btime); //这样简单的速度就可以计算出来 如果你想计算加速度 也可以 在运动学里,加速度a与速度, //位移都有关系:Vt=V0+at,S=V0*t+1/2at^2, S=(Vt^2-V0^2)/(2a),根据这些信息也可以求解a。 //这里就不详细介绍了 公事 应该初中物理课老师就教了呵呵~~ bx = x; by = y; bz = z; btime = System.currentTimeMillis(); } public void onAccuracyChanged(Sensor s, int accuracy) { } }; // 注册listener,第三个参数是检测的精确度 sensorMgr.registerListener(lsn, sensor, SensorManager.SENSOR_DELAY_GAME); |
下面给出这个DEMO小球重力感应的完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
import android.app.Activity; import android.content.Context; import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.Window; import android.view.WindowManager; import android.view.SurfaceHolder.Callback; public class SurfaceViewAcitvity extends Activity { MyView mAnimView = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 全屏显示窗口 requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //强制横屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // 显示自定义的游戏View mAnimView = new MyView(this); setContentView(mAnimView); } public class MyView extends SurfaceView implements Callback,Runnable ,SensorEventListener{ /**每50帧刷新一次屏幕**/ public static final int TIME_IN_FRAME = 50; /** 游戏画笔 **/ Paint mPaint = null; Paint mTextPaint = null; SurfaceHolder mSurfaceHolder = null; /** 控制游戏更新循环 **/ boolean mRunning = false; /** 游戏画布 **/ Canvas mCanvas = null; /**控制游戏循环**/ boolean mIsRunning = false; /**SensorManager管理器**/ private SensorManager mSensorMgr = null; Sensor mSensor = null; /**手机屏幕宽高**/ int mScreenWidth = 0; int mScreenHeight = 0; /**小球资源文件越界区域**/ private int mScreenBallWidth = 0; private int mScreenBallHeight = 0; /**游戏背景文件**/ private Bitmap mbitmapBg; /**小球资源文件**/ private Bitmap mbitmapBall; /**小球的坐标位置**/ private float mPosX = 200; private float mPosY = 0; /**重力感应X轴 Y轴 Z轴的重力值**/ private float mGX = 0; private float mGY = 0; private float mGZ = 0; public MyView(Context context) { super(context); /** 设置当前View拥有控制焦点 **/ this.setFocusable(true); /** 设置当前View拥有触摸事件 **/ this.setFocusableInTouchMode(true); /** 拿到SurfaceHolder对象 **/ mSurfaceHolder = this.getHolder(); /** 将mSurfaceHolder添加到Callback回调函数中 **/ mSurfaceHolder.addCallback(this); /** 创建画布 **/ mCanvas = new Canvas(); /** 创建曲线画笔 **/ mPaint = new Paint(); mPaint.setColor(Color.WHITE); /**加载小球资源**/ mbitmapBall = BitmapFactory.decodeResource(this.getResources(), R.drawable.ball); /**加载游戏背景**/ mbitmapBg = BitmapFactory.decodeResource(this.getResources(), R.drawable.bg); /**得到SensorManager对象**/ mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE); mSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); // 注册listener,第三个参数是检测的精确度 //SENSOR_DELAY_FASTEST 最灵敏 因为太快了没必要使用 //SENSOR_DELAY_GAME 游戏开发中使用 //SENSOR_DELAY_NORMAL 正常速度 //SENSOR_DELAY_UI 最慢的速度 mSensorMgr.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME); } private void Draw() { /**绘制游戏背景**/ mCanvas.drawBitmap(mbitmapBg,0,0, mPaint); /**绘制小球**/ mCanvas.drawBitmap(mbitmapBall, mPosX,mPosY, mPaint); /**X轴 Y轴 Z轴的重力值**/ mCanvas.drawText("X轴重力值 :" + mGX, 0, 20, mPaint); mCanvas.drawText("Y轴重力值 :" + mGY, 0, 40, mPaint); mCanvas.drawText("Z轴重力值 :" + mGZ, 0, 60, mPaint); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { /**开始游戏主循环线程**/ mIsRunning = true; new Thread(this).start(); /**得到当前屏幕宽高**/ mScreenWidth = this.getWidth(); mScreenHeight = this.getHeight(); /**得到小球越界区域**/ mScreenBallWidth = mScreenWidth - mbitmapBall.getWidth(); mScreenBallHeight = mScreenHeight - mbitmapBall.getHeight(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { mIsRunning = false; } @Override public void run() { while (mIsRunning) { /** 取得更新游戏之前的时间 **/ long startTime = System.currentTimeMillis(); /** 在这里加上线程安全锁 **/ synchronized (mSurfaceHolder) { /** 拿到当前画布 然后锁定 **/ mCanvas = mSurfaceHolder.lockCanvas(); Draw(); /** 绘制结束后解锁显示在屏幕上 **/ mSurfaceHolder.unlockCanvasAndPost(mCanvas); } /** 取得更新游戏结束的时间 **/ long endTime = System.currentTimeMillis(); /** 计算出游戏一次更新的毫秒数 **/ int diffTime = (int) (endTime - startTime); /** 确保每次更新时间为50帧 **/ while (diffTime <= TIME_IN_FRAME) { diffTime = (int) (System.currentTimeMillis() - startTime); /** 线程等待 **/ Thread.yield(); } } } @Override public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } @Override public void onSensorChanged(SensorEvent event) { mGX = event.values[SensorManager.DATA_X]; mGY= event.values[SensorManager.DATA_Y]; mGZ = event.values[SensorManager.DATA_Z]; //这里乘以2是为了让小球移动的更快 mPosX -= mGX * 2; mPosY += mGY * 2; //检测小球是否超出边界 if (mPosX < 0) { mPosX = 0; } else if (mPosX > mScreenBallWidth) { mPosX = mScreenBallWidth; } if (mPosY < 0) { mPosY = 0; } else if (mPosY > mScreenBallHeight) { mPosY = mScreenBallHeight; } } } } |
老规矩每篇文章都会附带源代码,最后如果你还是觉得我写的不够详细 看的不够爽 不要紧我把源代码的下载地址贴出来 欢迎大家一起讨论学习雨松MOMO希望可以和大家一起进步。
- 本文固定链接: https://www.xuanyusong.com/archives/337
- 转载请注明: 雨松MOMO 于 雨松MOMO程序研究院 发表
使用了网上一个GyroDroid 陀螺仪的插件, 但是极其不稳定 在场景里面放一个cube 用手机旋转看的时候 cube基本上是飘的 有什么办法能让他不那么晃
MOMO大神,请教下,我在android下的陀螺仪数据抖动是什么情况啊,用了网上随便一搜就能找到的陀螺仪控制摄像机的代码,但是打包到IOS上一点问题都没有。在android上就会自己跳动,摄像机也会在手机静止状态下自己慢慢转动。用了低通过滤器也不好使。偶尔还会大幅度的跳动一个角度。
大神,在Unity下 有直接使用的Sensor功能 或者 插件吗? 求推荐。。。
Input.acceleration.x Input.acceleration.y看看这个吧。。