首頁(yè) 收藏 QQ群
 網(wǎng)站導(dǎo)航

ZNDS智能電視網(wǎng) 推薦當(dāng)貝市場(chǎng)

TV應(yīng)用下載 / 資源分享區(qū)

軟件下載 | 游戲 | 討論 | 電視計(jì)算器

綜合交流 / 評(píng)測(cè) / 活動(dòng)區(qū)

交流區(qū) | 測(cè)硬件 | 網(wǎng)站活動(dòng) | Z幣中心

新手入門 / 進(jìn)階 / 社區(qū)互助

新手 | 你問(wèn)我答 | 免費(fèi)刷機(jī)救磚 | ROM固件

查看: 11769|回復(fù): 0
上一主題 下一主題
[教程]

Android游戲開發(fā)之小球重力感應(yīng)實(shí)現(xiàn)(二十五)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2013-8-28 16:19 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
41016Android游戲開發(fā)之小球重力感應(yīng)實(shí)現(xiàn)   
     
重力感應(yīng)主要是依靠手機(jī)的加速度傳感器(accelerometer)來(lái)實(shí)現(xiàn)   
   
        在Android的開發(fā)中一共有八種傳感器但是不一定每一款真機(jī)都支持這些傳感器。因?yàn)楹芏喙δ苡脩舾静籧are的所以可能開發(fā)商會(huì)把某些功能屏蔽掉。還是得根據(jù)真機(jī)的實(shí)際情況來(lái)做開發(fā),今天我們主要來(lái)討論加速度傳感器的具體實(shí)現(xiàn)方式。   
   
   
   
傳感器名稱如下:   
   
加速度傳感器(accelerometer)   
陀螺儀傳感器(gyroscope)   
環(huán)境光照傳感器(light)   
磁力傳感器(magnetic field)   
方向傳感器(orientation)   
壓力傳感器(pressure)   
距離傳感器(proximity)   
溫度傳感器(temperature)   
   
   
   
   
   
1.SensorMannager傳感器管理對(duì)象   
   
手機(jī)中的所有傳感器都須要通過(guò)SensorMannager來(lái)訪問(wèn),調(diào)用getSystemService(SENSOR_SERVICE)方法就可以拿到當(dāng)前手機(jī)的傳感器管理對(duì)象。   
  1. SensorManager mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);  
復(fù)制代碼
2.實(shí)現(xiàn)SensorEventListener接口   
   
       說(shuō)道SensorEventListener接口就不得不說(shuō)SensorListener接口。在Android1.5一下是通過(guò)實(shí)現(xiàn)SensorListener接口來(lái)捕獲 手機(jī)傳感器狀態(tài),但是在1.5以上如果實(shí)現(xiàn)這個(gè)接口系統(tǒng)會(huì)提示你這行代碼已經(jīng)過(guò)期。今天我們不討論SensorListener因?yàn)樗呀?jīng)是過(guò)時(shí)的東西了。主要討論一下SensorEventListener接口。我們須要實(shí)現(xiàn)SensorEventListener這個(gè)接口 onSensorChanged(SensorEvent event)方法來(lái)捕獲手機(jī)傳感器的狀態(tài),拿到手機(jī) X軸Y軸Z軸三個(gè)方向的重力分量,有了這三個(gè)方向的數(shù)據(jù)重力感應(yīng)的原理我們就已經(jīng)學(xué)會(huì)了,簡(jiǎn)單吧   
  1.         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];         
            }   
復(fù)制代碼
如圖所示:上例代碼中 float x y z 3個(gè)方向的取值范圍是在 -10 到 10 之間,我向同學(xué)們說(shuō)明一下 X軸 Y軸 Z軸 重力分量的含義。 這里須要注意的是坐標(biāo)原點(diǎn) 向天空為正數(shù) 向地面為負(fù)數(shù) 剛好與編程時(shí)坐標(biāo)是相反的。   
   
手機(jī)屏幕向左側(cè)方當(dāng)X軸就朝向天空,垂直放置 這時(shí)候 Y 軸 與 Z軸沒(méi)有重力分量,因?yàn)閄軸朝向天空所以它的重力分量則最大 。這時(shí)候X軸 Y軸 Z軸的重力分量的值分別為(10,0,0)   
   
手機(jī)屏幕向右側(cè)方當(dāng)X軸就朝向地面,垂直放置 這時(shí)候 Y 軸 與 Z軸沒(méi)有重力分量,因?yàn)閄軸朝向地面所以它的重力分量則最小 。這時(shí)候X軸 Y軸 Z軸的重力分量的值分別為(-10,0,0)   
   
手機(jī)屏幕垂直豎立放置方當(dāng)Y軸就朝向天空,垂直放置 這時(shí)候 X 軸 與 Z軸沒(méi)有重力分量,因?yàn)閅軸朝向天空所以它的重力分量則最大 。這時(shí)候X軸 Y軸 Z軸的重力分量的值分別為(0,10,0)   
   
手機(jī)屏幕垂直豎立放置方當(dāng)Y軸就朝向地面,垂直放置 這時(shí)候 X 軸 與 Z軸沒(méi)有重力分量,因?yàn)閅軸朝向地面所以它的重力分量則最小 。這時(shí)候X軸 Y軸 Z軸的重力分量的值分別為(0,-10,0)   
   
   
手機(jī)屏幕向上當(dāng)Z軸就朝向天空,水平放置 這時(shí)候 X 軸與Y軸沒(méi)有重力分量,因?yàn)閆軸朝向天空所以它的重力分量則最大 。這時(shí)候X軸 Y軸 Z軸的重力分量的值分別為(0,0,10)   
   
手機(jī)屏幕向上當(dāng)Z軸就朝向地面,水平放置 這時(shí)候 X 軸與Y軸沒(méi)有重力分量,因?yàn)閆軸朝向地面所以它的重力分量則最小 。這時(shí)候X軸 Y軸 Z軸的重力分量的值分別為(0,0,-10)   
   
因?yàn)檫@張圖片是在模擬器上截得,所以沒(méi)有重力感應(yīng)它的三個(gè)方向的的重力分量都為0。   
   
     
3.注冊(cè)SensorEventListener   
   
   
         使用SensorMannager調(diào)用getDefaultSensor(Sensor.TYPE_ACCELEROMETER)方法拿到加速重力感應(yīng)的Sensor對(duì)象。因?yàn)楸菊挛覀冇懻撝亓铀俣葌鞲衅魉詤?shù)為Sensor.TYPE_ACCELEROMETER,如果須要拿到其它的傳感器須要傳入對(duì)應(yīng)的名稱。使用SensorMannager調(diào)用registerListener()方法來(lái)注冊(cè),第三個(gè)參數(shù)是檢測(cè)的靈敏精確度根據(jù)不同的需求來(lái)選擇精準(zhǔn)度,游戲開發(fā)建議使用  SensorManager.SENSOR_DELAY_GAME。   
  1.             mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);      
                mSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);      
                // 注冊(cè)listener,第三個(gè)參數(shù)是檢測(cè)的精確度     
                //SENSOR_DELAY_FASTEST 最靈敏 因?yàn)樘炝藳](méi)必要使用   
                //SENSOR_DELAY_GAME    游戲開發(fā)中使用   
                //SENSOR_DELAY_NORMAL  正常速度   
                //SENSOR_DELAY_UI                最慢的速度   
                mSensorMgr.registerListener(this, mSensor, SensorManager.SENSOR_DELAY_GAME);  
復(fù)制代碼
重力感應(yīng)簡(jiǎn)單速度計(jì)算的方式。 每次搖晃手機(jī)計(jì)算出 X軸 Y軸 Z軸的重力分量可以將它們記錄下來(lái) 然后每次搖晃的重力分量和之前的重力分量可以做一個(gè)對(duì)比 利用差值和時(shí)間就可以計(jì)算出他們的移動(dòng)速度。(下面這段代碼是我之前的博文中摘錄過(guò)來(lái)的,因?yàn)槟瞧獙懙牟皇呛芎盟栽谶@一篇中我詳細(xì)總結(jié)一下)   
  1.     private SensorManager sensorMgr;      
        Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);        
             
         //保存上一次 x y z 的坐標(biāo)     
         float bx = 0;     
         float by = 0;     
         float bz = 0;     
         long btime = 0;//這一次的時(shí)間      
         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];      
                   //在這里我們可以計(jì)算出 X Y Z的數(shù)值 下面我們就可以根據(jù)這個(gè)數(shù)值來(lái)計(jì)算搖晃的速度了      
                   //我想大家應(yīng)該都知道計(jì)算速度的公事 速度 = 路程/時(shí)間     
                   //X軸的速度     
                   float speadX = (x - bx) / (System.currentTimeMillis() - btime);      
                   //y軸的速度     
                   float speadY = (y - by) / (System.currentTimeMillis() - btime);      
                   //z軸的速度     
                   float speadZ = (z - bz) / (System.currentTimeMillis() - btime);      
                   //這樣簡(jiǎn)單的速度就可以計(jì)算出來(lái) 如果你想計(jì)算加速度 也可以 在運(yùn)動(dòng)學(xué)里,加速度a與速度,     
                   //位移都有關(guān)系:Vt=V0+at,S=V0*t+1/2at^2, S=(Vt^2-V0^2)/(2a),根據(jù)這些信息也可以求解a。      
                   //這里就不詳細(xì)介紹了 公事 應(yīng)該初中物理課老師就教了呵呵~~     
             
                   bx = x;     
                   by = y;     
                   bz = z;     
             
                   btime = System.currentTimeMillis();     
             
             
                }        
                        
                public void onAccuracyChanged(Sensor s, int accuracy) {        
                }        
            };        
            // 注冊(cè)listener,第三個(gè)參數(shù)是檢測(cè)的精確度     
            sensorMgr.registerListener(lsn, sensor, SensorManager.SENSOR_DELAY_GAME);  
復(fù)制代碼
真機(jī)上的效果圖   
   
     
下面給出這個(gè)DEMO小球重力感應(yīng)的完整代碼   
  1. 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);   
            //強(qiáng)制橫屏   
            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;   
       
            /** 控制游戲更新循環(huán) **/   
            boolean mRunning = false;   
       
            /** 游戲畫布 **/   
            Canvas mCanvas = null;   
       
            /**控制游戲循環(huán)**/   
            boolean mIsRunning = false;   
               
            /**SensorManager管理器**/   
            private SensorManager mSensorMgr = null;      
            Sensor mSensor = null;      
               
            /**手機(jī)屏幕寬高**/   
            int mScreenWidth = 0;   
            int mScreenHeight = 0;   
               
            /**小球資源文件越界區(qū)域**/   
            private int mScreenBallWidth = 0;   
            private int mScreenBallHeight = 0;   
               
            /**游戲背景文件**/   
            private Bitmap mbitmapBg;   
               
            /**小球資源文件**/   
            private Bitmap mbitmapBall;   
               
            /**小球的坐標(biāo)位置**/   
            private float mPosX = 200;   
            private float mPosY = 0;   
               
            /**重力感應(yīng)X軸 Y軸 Z軸的重力值**/   
            private float mGX = 0;   
            private float mGY = 0;   
            private float mGZ = 0;   
               
            public MyView(Context context) {   
                super(context);   
                /** 設(shè)置當(dāng)前View擁有控制焦點(diǎn) **/   
                this.setFocusable(true);   
                /** 設(shè)置當(dāng)前View擁有觸摸事件 **/   
                this.setFocusableInTouchMode(true);   
                /** 拿到SurfaceHolder對(duì)象 **/   
                mSurfaceHolder = this.getHolder();   
                /** 將mSurfaceHolder添加到Callback回調(diào)函數(shù)中 **/   
                mSurfaceHolder.addCallback(this);   
                /** 創(chuàng)建畫布 **/   
                mCanvas = new Canvas();   
                /** 創(chuàng)建曲線畫筆 **/   
                mPaint = new Paint();   
                mPaint.setColor(Color.WHITE);   
                /**加載小球資源**/   
                mbitmapBall = BitmapFactory.decodeResource(this.getResources(), R.drawable.ball);   
                /**加載游戲背景**/   
                mbitmapBg = BitmapFactory.decodeResource(this.getResources(), R.drawable.bg);   
                   
                /**得到SensorManager對(duì)象**/   
                mSensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);      
                mSensor = mSensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);      
                // 注冊(cè)listener,第三個(gè)參數(shù)是檢測(cè)的精確度     
                //SENSOR_DELAY_FASTEST 最靈敏 因?yàn)樘炝藳](méi)必要使用   
                //SENSOR_DELAY_GAME    游戲開發(fā)中使用   
                //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) {   
                /**開始游戲主循環(huán)線程**/   
                mIsRunning = true;   
                new Thread(this).start();   
                /**得到當(dāng)前屏幕寬高**/   
                mScreenWidth = this.getWidth();   
                mScreenHeight = this.getHeight();   
                   
                /**得到小球越界區(qū)域**/   
                mScreenBallWidth = mScreenWidth - mbitmapBall.getWidth();   
                mScreenBallHeight = mScreenHeight - mbitmapBall.getHeight();   
            }   
       
            @Override   
            public void surfaceDestroyed(SurfaceHolder holder) {   
                mIsRunning = false;   
            }   
       
            @Override   
            public void run() {   
                while (mIsRunning) {   
       
                    /** 取得更新游戲之前的時(shí)間 **/   
                    long startTime = System.currentTimeMillis();   
       
                    /** 在這里加上線程安全鎖 **/   
                    synchronized (mSurfaceHolder) {   
                        /** 拿到當(dāng)前畫布 然后鎖定 **/   
                        mCanvas = mSurfaceHolder.lockCanvas();   
                        Draw();   
                        /** 繪制結(jié)束后解鎖顯示在屏幕上 **/   
                        mSurfaceHolder.unlockCanvasAndPost(mCanvas);   
                    }   
       
                    /** 取得更新游戲結(jié)束的時(shí)間 **/   
                    long endTime = System.currentTimeMillis();   
       
                    /** 計(jì)算出游戲一次更新的毫秒數(shù) **/   
                    int diffTime = (int) (endTime - startTime);   
       
                    /** 確保每次更新時(shí)間為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是為了讓小球移動(dòng)的更快   
                mPosX -= mGX * 2;   
                mPosY += mGY * 2;   
       
                //檢測(cè)小球是否超出邊界   
                if (mPosX < 0) {   
                    mPosX = 0;   
                } else if (mPosX > mScreenBallWidth) {   
                    mPosX = mScreenBallWidth;   
                }   
                if (mPosY < 0) {   
                    mPosY = 0;   
                } else if (mPosY > mScreenBallHeight) {   
                    mPosY = mScreenBallHeight;   
                }   
            }   
        }   
    }
復(fù)制代碼
老規(guī)矩每篇文章都會(huì)附帶源代碼,最后如果你還是覺(jué)得我寫的不夠詳細(xì) 看的不夠爽 不要緊我把源代碼的下載地址貼出來(lái) 歡迎大家一起討論學(xué)習(xí)   
第十五講重力感應(yīng).rar(1.65 MB, 下載次數(shù): 2300)[/I]2011-9-3 01:00 上傳點(diǎn)擊文件名   下載積分: 下載豆 -2

上一篇:第十六講:菜單 Android Menu
下一篇:第十四講:Service入門指南

本版積分規(guī)則

Archiver|新帖|標(biāo)簽|軟件|Sitemap|ZNDS智能電視網(wǎng) ( 蘇ICP備2023012627號(hào) )

網(wǎng)絡(luò)信息服務(wù)信用承諾書 | 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證:蘇B2-20221768 丨 蘇公網(wǎng)安備 32011402011373號(hào)

GMT+8, 2024-10-21 06:26 , Processed in 0.061599 second(s), 14 queries , Redis On.

Powered by Discuz!

監(jiān)督舉報(bào):report#znds.com (請(qǐng)將#替換為@)

© 2007-2024 ZNDS.Com

快速回復(fù) 返回頂部 返回列表