1,重力感应主要是用到SensorManager,获取小球在各个方向的加速度,以改变小球的位置来实现重力感应
以屏幕的左下方为原点(2d编程的时候,是以屏幕左上方为原点的,这个值得注意一下),箭头指向的方向为正。
从-10到10,以浮点数为等级单位,想象一下以下情形:
手机屏幕向上(z轴朝天)水平放置的时侯,(x,y,z)的值分别为(0,0,10);
手机屏幕向下(z轴朝地)水平放置的时侯,(x,y,z)的值分别为(0,0,-10);
手机屏幕向左侧放(x轴朝天)的时候,(x,y,z)的值分别为(10,0,0);
手机竖直(y轴朝天)向上的时候,(x,y,z)的值分别为(0,10,0);
其他的如此类推,规律就是:朝天的就是正数,朝地的就是负数。利用x,y,z三个值求三角函数,就可以精确检测手机的运动状态了。
import android.os.Bundle;
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.graphics.RectF;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.Menu;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
public class MainActivity extends Activity {
MyView mAnimView = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_gravity);
requestWindowFeature(Window.FEATURE_NO_TITLE); //全屏显示窗口
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); //强制横屏
mAnimView = new MyView(this); // 显示自定义的游戏View
setContentView(mAnimView);
}
public class MyView extends SurfaceView implements Callback,Runnable ,SensorEventListener{
public static final int TIME_IN_FRAME = 50; //每50帧刷新一次屏幕
Paint mPaint = null; //游戏画笔
Paint mTextPaint = null;
SurfaceHolder mSurfaceHolder = null;
boolean mRunning = false; // 控制游戏更新循环
Canvas mCanvas = null; //游戏画布
Canvas mycan;
Bitmap mypic;
boolean mIsRunning = false; //**控制游戏循环**/
private SensorManager mSensorMgr = null; //SensorManager管理器
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;
private float mGX = 0; //**重力感应X轴 Y轴 Z轴的重力值**/
private float mGY = 0;
private float mGZ = 0;
int width,height;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.setFocusable(true); //** 设置当前View拥有控制焦点 **/
this.setFocusableInTouchMode(true); //** 设置当前View拥有触摸事件 **/
mSurfaceHolder = this.getHolder(); //** 拿到SurfaceHolder对象 **/
mSurfaceHolder.addCallback(this); //** 将mSurfaceHolder添加到Callback回调函数中 **/
mCanvas = new Canvas(); //** 创建画布 **/
mPaint = new Paint(); //** 创建曲线画笔 **/
mPaint.setColor(Color.WHITE);
mbitmapBall = BitmapFactory.decodeResource(this.getResources(), R.drawable.flower); //**加载小球资源**/
mbitmapBg = BitmapFactory.decodeResource(this.getResources(), R.drawable.underground); //**加载游戏背景**/
mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE); //**得到SensorManager对象**/
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() {
RectF new_rect = new RectF(0, 0, width, height);
mCanvas.drawBitmap(mbitmapBg, null, new_rect, mPaint);
//
// mCanvas.drawBitmap(mbitmapBg, getClipBounds(), getClipBounds(), mPaint);
// mCanvas.drawBitmap(mbitmapBg,0,0, mPaint); //**绘制游戏背景**/
mCanvas.drawBitmap(mbitmapBall, mPosY,mPosX, mPaint); //**绘制小球**/
mCanvas.drawText("X轴重力值 :" + mGX, 0, 20, mPaint); //**X轴 Y轴 Z轴的重力值**/
mCanvas.drawText("Y轴重力值 :" + mGY, 0, 40, mPaint);
mCanvas.drawText("Z轴重力值 :" + mGZ, 0, 60, mPaint);
}
@Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
// TODO Auto-generated method stub
}
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub //获取小球在各个方向的加速度,以改变小球的位置来实现重力感应
mGX = event.values[SensorManager.DATA_X];
mGY= event.values[SensorManager.DATA_Y];
mGZ = event.values[SensorManager.DATA_Z];
mPosX += mGX * 0.5; //这里乘以2是为了让小球移动的更快
mPosY += mGY * 0.5;
//检测小球是否超出边界
if (mPosX < 0) {
mPosX = 0;
} else if (mPosX > mScreenBallHeight) {
mPosX = mScreenBallHeight;
}
if (mPosY < 0) {
mPosY = 0;
} else if (mPosY > mScreenBallWidth) {
mPosY = mScreenBallWidth;
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while (mIsRunning) {
long startTime = System.currentTimeMillis(); //** 取得更新游戏之前的时间 **/
synchronized (mSurfaceHolder) { //** 在这里加上线程安全锁 **/
mCanvas = mSurfaceHolder.lockCanvas(); //** 拿到当前画布 然后锁定 **/
Draw();
mSurfaceHolder.unlockCanvasAndPost(mCanvas); // 绘制结束后解锁显示在屏幕上 **/
}
long endTime = System.currentTimeMillis(); //** 取得更新游戏结束的时间 **/
int diffTime = (int) (endTime - startTime); //** 计算出游戏一次更新的毫秒数 **/
while (diffTime <= TIME_IN_FRAME) { //** 确保每次更新时间为50帧 **/
diffTime = (int) (System.currentTimeMillis() - startTime);
Thread.yield(); //** 线程等待 **/
}
}
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
mIsRunning = true; //**开始游戏主循环线程**/
new Thread(this).start(); //**得到当前屏幕宽高**/
mScreenWidth = this.getWidth();
mScreenHeight = this.getHeight();
mScreenBallWidth = mScreenWidth - mbitmapBall.getWidth(); //**得到小球越界区域**/
mScreenBallHeight = mScreenHeight - mbitmapBall.getHeight();
width=this.getWidth();
height=this.getHeight();
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
mIsRunning = false;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}