物理小球在遊戲中的應用

遊戲編程需要一些經常使用的數學和物理知識,下面演示一下:

1、開發運動體Movable類代碼

  1. package wyf.wpf;        //聲明包語句  
  2. import android.graphics.Bitmap; //引入相關類  
  3. import android.graphics.Canvas; //引入相關類  
  4. //代表可移動物體的Movable類  
  5. public class Movable{  
  6.     int startX=0;       //初始X座標  
  7.     int startY=0;       //初始Y座標  
  8.     int x;              //實時X座標  
  9.     int y;              //實時Y座標  
  10.     float startVX=0f;   //初始豎直方向的速度  
  11.     float startVY=0f;   //初始水平方向的速度  
  12.     float v_x=0f;       //實時水平方向速度  
  13.     float v_y=0f;       //實時豎直方向速度  
  14.     int r;              //可移動物體半徑  
  15.     double timeX;           //X方向上的運動時間  
  16.     double timeY;           //Y方向上的運動時間  
  17.     Bitmap bitmap=null//可移動物體圖片  
  18.     BallThread bt=null//負責小球移動時 ,作爲一個線程,起到物理引擎的作用 
  19.     boolean bFall=false;//小球是否已經從木板上下落  
  20.     float impactFactor = 0.25f; //小球撞地後速度的損失係數  
  21.     //構造器  
  22.     public Movable(int x,int y,int r,Bitmap bitmap){  
  23.         this.startX = x;        //初始化X座標  
  24.         this.x = x;             //初始化X座標  
  25.         this.startY = y;        //初始化Y座標  
  26.         this.y = y;             //初始化Y座標  
  27.         this.r = r;             //初始化  
  28.         this.bitmap = bitmap;   //初始化圖片  
  29.         timeX=System.nanoTime();    //獲取系統時間初始化  
  30.         this.v_x = BallView.V_MIN + (int)((BallView.V_MAX-BallView.V_MIN)*Math.random());         
  31.         bt = new BallThread(this);//創建並啓動BallThread ,啓動物理引擎
  32.         bt.start();  
  33.     }  
  34.     //方法:繪製自己到屏幕上  
  35.     public void drawSelf(Canvas canvas){  
  36.         canvas.drawBitmap(this.bitmap,x, y, null);  
  37.     }  

2、開發物理引擎BallThread類的代碼

     這次物理引擎的工作機制:

  • 座標系統
  • 運動階段
  • 數值計算
  • 爲零判斷
  1. package wyf.wpf;                //聲明包語句  
  2. //繼承自Thread的線程類,負責修改球的位置座標  
  3. public class BallThread extends Thread{   
  4.     Movable father;     //Movable對象引用  
  5.     boolean flag = false;   //線程執行標誌位  
  6.     int sleepSpan = 30;     //休眠時間  
  7.     float g = 200;      //球下落的加速度  
  8.     double current; //記錄當前時間  
  9.     //構造器:初始化Movable對象引用及線程執行標誌位  
  10.     public BallThread(Movable father){  
  11.         this.father = father;  
  12.         this.flag = true;       //設置線程執行的標誌位爲true  
  13.     }  
  14.     //方法:負責根據物理公式修改小球位置,並檢測和處理小球達到最高點以及撞擊地面的事件  
  15.     public void run(){  
  16.         while(flag){  
  17.             current = System.nanoTime();//獲取當前時間,單位爲納秒  
  18.             double timeSpanX = (double)((current-father.timeX)/1000/1000/1000);//獲取從玩家開始到現在水平方向走過的時間  
  19.             //處理水平方向上的運動  
  20.             father.x = (int)(father.startX + father.v_x * timeSpanX);  
  21.             //處理豎直方向上的運動              
  22.             if(father.bFall){//判斷球是否已經移出擋板  
  23.                 double timeSpanY = (double)((current - father.timeY)/1000/1000/1000);     
  24.                 father.y = (int)(father.startY + father.startVY * timeSpanY + timeSpanY*timeSpanY*g/2);  
  25.                 father.v_y = (float)(father.startVY + g*timeSpanY);               
  26.                 //判斷小球是否到達最高點  
  27.                 if(father.startVY < 0 && Math.abs(father.v_y) <= BallView.UP_ZERO){  
  28.                     father.timeY = System.nanoTime();           //設置新的運動階段豎直方向上的開始時間  
  29.                     father.v_y = 0;                             //設置新的運動階段豎直方向上的實時速度  
  30.                     father.startVY = 0;                         //設置新的運動階段豎直方向上的初始速度  
  31.                     father.startY = father.y;                   //設置新的運動階段豎直方向上的初始位置  
  32.                 }  
  33.                 //判斷小球是否撞地  
  34.                 if(father.y + father.r*2 >= BallView.GROUND_LING && father.v_y >0){//判斷撞地條件  
  35.                     //改變水平方向的速度  
  36.                     father.v_x = father.v_x * (1-father.impactFactor);  //衰減水平方向上的速度  
  37.                     //改變豎直方向的速度  
  38.                     father.v_y = 0 - father.v_y * (1-father.impactFactor);      //衰減豎直方向上的速度並改變方向  
  39.                     if(Math.abs(father.v_y) < BallView.DOWN_ZERO){  //判斷撞地後的速度,太小就停止  
  40.                         this.flag = false;  
  41.                     }  
  42.                     else{   //撞地後的速度還可以彈起繼續下一階段的運動  
  43.                         //撞地之後水平方向的變化  
  44.                         father.startX = father.x;           //設置新的運動階段的水平方向的起始位置  
  45.                         father.timeX = System.nanoTime();   //設置新的運動階段的水平方向的開始時間  
  46.                         //撞地之後豎直方向的變化                         
  47.                         father.startY = father.y;       //設置新的運動階段豎直方向上的起始位置  
  48.                         father.timeY = System.nanoTime();   //設置新的運動階段豎直方向開始運動的時間  
  49.                         father.startVY = father.v_y;    //設置新的運動階段豎直方向上的初速度  
  50.                     }  
  51.                 }                 
  52.             }  
  53.             else if(father.x + father.r/2 >= BallView.WOOD_EDGE){//判斷球是否移出了擋板             
  54.                 father.timeY = System.nanoTime();       //記錄球豎直方向上的開始運動時間  
  55.                 father.bFall = true;                //設置表示是否開始下落標誌位  
  56.             }             
  57.             try{  
  58.                 Thread.sleep(sleepSpan);        //休眠一段時間                  
  59.             }  
  60.             catch(Exception e){  
  61.                 e.printStackTrace();  
  62.             }  
  63.         }  
  64.     }  

3、視圖類--開發BallView類的代碼

 

  1. package wyf.wpf;        //聲明包語句  
  2. import java.util.ArrayList;     //引入相關類  
  3. import java.util.Random;        //引入相關類  
  4. import android.content.Context; //引入相關類  
  5. import android.content.res.Resources;   //引入相關類  
  6. import android.graphics.Bitmap;         //引入相關類  
  7. import android.graphics.BitmapFactory;  //引入相關類  
  8. import android.graphics.Canvas;         //引入相關類  
  9. import android.graphics.Color;          //引入相關類  
  10. import android.graphics.Paint;          //引入相關類  
  11. import android.view.SurfaceHolder;      //引入相關類  
  12. import android.view.SurfaceView;        //引入相關類  
  13. //繼承自SurfaceView的子類 ,需要實現SurfaceHolder.callback接口  
  14. public class BallView extends SurfaceView implements SurfaceHolder.Callback{  
  15.     public static final int V_MAX=35;   //小球水平速度的最大值  
  16.     public static final int V_MIN=15;   //小球豎直速度的最大值  
  17.     public static final int WOOD_EDGE = 60//木板的右邊沿的x座標  
  18.     public static final int GROUND_LING = 450;//遊戲中代表地面y座標,小球下落到此會彈起   
  19.     public static final int UP_ZERO = 30;   //小球在上升過程中,如果速度大小小於該值就算爲0  
  20.     public static final int DOWN_ZERO = 60//小球在撞擊地面後,如果速度大小小於該值就算爲0  
  21.     Bitmap [] bitmapArray = new Bitmap[6];  //各種顏色形狀的小球圖片引用  
  22.     Bitmap bmpBack;     //背景圖片對象  
  23.     Bitmap bmpWood;     //木板圖片對象  
  24.     String fps="FPS:N/A";       //用於顯示幀速率的字符串,調試使用    
  25.     int ballNumber =8;  //小球數目  
  26.     ArrayList<Movable> alMovable = new ArrayList<Movable>();    //小球對象數組  
  27.     DrawThread dt;  //後臺屏幕繪製線程  
  28.  
  29.     public BallView(Context activity){  
  30.         super(activity);                //調用父類構造器         
  31.         getHolder().addCallback(this);  
  32.         initBitmaps(getResources());    //初始化圖片       
  33.         initMovables();                 //初始化小球       
  34.         dt = new DrawThread(this,getHolder());      //初始化重繪線程         
  35.     }  
  36.     //方法:初始化圖片  
  37.     public void initBitmaps(Resources r){  
  38.         bitmapArray[0] = BitmapFactory.decodeResource(r, R.drawable.ball_red_small);    //紅色較小球  
  39.         bitmapArray[1] = BitmapFactory.decodeResource(r, R.drawable.ball_purple_small); //紫色較小球  
  40.         bitmapArray[2] = BitmapFactory.decodeResource(r, R.drawable.ball_green_small);  //綠色較小球       
  41.         bitmapArray[3] = BitmapFactory.decodeResource(r, R.drawable.ball_red);          //紅色較大球  
  42.         bitmapArray[4] = BitmapFactory.decodeResource(r, R.drawable.ball_purple);       //紫色較大球  
  43.         bitmapArray[5] = BitmapFactory.decodeResource(r, R.drawable.ball_green);        //綠色較大球  
  44.         bmpBack = BitmapFactory.decodeResource(r, R.drawable.back);                     //背景磚牆  
  45.         bmpWood = BitmapFactory.decodeResource(r, R.drawable.wood);                     //木板  
  46.     }  
  47.     //方法:初始化小球  
  48.     public void initMovables(){  
  49.         Random r = new Random();    //創建一個Random對象  
  50.         for(int i=0;i<ballNumber;i++){  
  51.             int index = r.nextInt(32);      //產生隨機數  
  52.             Bitmap tempBitmap=null;         //聲明一個Bitmap圖片引用  
  53.             if(i<ballNumber/2){       
  54.                 tempBitmap = bitmapArray[3+index%3];//如果是初始化前一半球,就從大球中隨機找一個  
  55.             }  
  56.             else{  
  57.                 tempBitmap = bitmapArray[index%3];//如果是初始化後一半球,就從小球中隨機找一個  
  58.             }  
  59.             Movable m = new Movable(0,70-tempBitmap.getHeight(),tempBitmap.getWidth()/2,tempBitmap);    //創建Movable對象  
  60.             alMovable.add(m);   //將新建的Movable對象添加到ArrayList列表中  
  61.         }  
  62.     }  
  63.     //方法:繪製程序中所需要的圖片等信息  
  64.     public void doDraw(Canvas canvas) {       
  65.         canvas.drawBitmap(bmpBack, 00null); //繪製背景圖片  
  66.         canvas.drawBitmap(bmpWood, 060null);//繪製木板圖片  
  67.         for(Movable m:alMovable){   //遍歷Movable列表,繪製每個Movable對象  
  68.             m.drawSelf(canvas);  
  69.         }  
  70.         Paint p = new Paint();  //創建畫筆對象  
  71.         p.setColor(Color.BLUE); //爲畫筆設置顏色  
  72.         p.setTextSize(18);      //爲畫筆設置字體大小  
  73.         p.setAntiAlias(true);   //設置抗鋸齒   
  74.         canvas.drawText(fps, 3030, p);    //畫出幀速率字符串  
  75.     }  
  76.     @Override 
  77.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  78.             int height) {//重寫surfaceChanged方法     
  79.     }  
  80.     @Override 
  81.     public void surfaceCreated(SurfaceHolder holder) {//從寫surfaceCreated方法  
  82.         if(!dt.isAlive()){  //如果DrawThread沒有啓動,就啓動這個線程  
  83.             dt.start();  
  84.         }  
  85.     }  
  86.     @Override 
  87.     public void surfaceDestroyed(SurfaceHolder holder) {//重寫surfaceDestroyed方法  
  88.         dt.flag = false;    //停止線程的執行  
  89.         dt = null;          //將dt指向的對象聲明爲垃圾  
  90.     }     

4、繪製線程--DrawThread類

主要負責定時重繪屏幕和計算幀速率

 

  1. package wyf.wpf;                //聲明包語句  
  2. import android.graphics.Canvas;     //引入相關類  
  3. import android.view.SurfaceHolder;  //引入相關類  
  4. public class DrawThread extends Thread{  
  5.     BallView bv;                //BallView對象引用  
  6.     SurfaceHolder surfaceHolder;//SurfaceHolder對象引用  
  7.     boolean flag=false;         //線程執行標誌位  
  8.     int sleepSpan = 30;         //休眠時間  
  9.     long start = System.nanoTime(); //記錄起始時間,該變量用於計算幀速率  
  10.     int count=0;        //記錄幀數,該變量用於計算幀速率  
  11.     //構造器  
  12.     public DrawThread(BallView bv,SurfaceHolder surfaceHolder){  
  13.         this.bv = bv;       //爲BallView對象應用賦值  
  14.         this.surfaceHolder = surfaceHolder; //爲SurfaceHolder對象應用賦值  
  15.         this.flag = true;       //設置標誌位  
  16.     }  
  17.     //方法:線程的執行方法,用於繪製屏幕和計算幀速率  
  18.     public void run(){  
  19.         Canvas canvas = null;//聲明一個Canvas對象  
  20.         while(flag){  
  21.             try{  
  22.                 canvas = surfaceHolder.lockCanvas(null);//獲取BallView的畫布  
  23.                 synchronized(surfaceHolder){  
  24.                     bv.doDraw(canvas);      //調用BallView的doDraw方法進行繪製  
  25.                 }  
  26.             }  
  27.             catch(Exception e){  
  28.                 e.printStackTrace();            //捕獲並打印異常  
  29.             }  
  30.             finally{  
  31.                 if(canvas != null){     //如果canvas不爲空  
  32.                     surfaceHolder.unlockCanvasAndPost(canvas);//surfaceHolder解鎖並將畫布對象傳回  
  33.                 }  
  34.             }         
  35.             this.count++;  
  36.             if(count == 20){    //如果計滿20幀  
  37.                 count = 0;      //清空計數器  
  38.                 long tempStamp = System.nanoTime();//獲取當前時間  
  39.                 long span = tempStamp - start;      //獲取時間間隔  
  40.                 start = tempStamp;                  //爲start重新賦值  
  41.                 double fps = Math.round(100000000000.0/span*20)/100.0;//計算幀速率  
  42.                 bv.fps = "FPS:"+fps;//將計算出的幀速率設置到BallView的相應字符串對象中  
  43.             }  
  44.             try{  
  45.                 Thread.sleep(sleepSpan);        //線程休眠一段時間  
  46.             }  
  47.             catch(Exception e){                   
  48.                 e.printStackTrace();        //捕獲並打印異常  
  49.             }  
  50.         }  
  51.     }     

5、Activity代碼

 

  1. package wyf.wpf;        //聲明包語句  
  2. import android.app.Activity;    //引入相關類  
  3. import android.os.Bundle;   //引入相關類  
  4. import android.view.Window;//引入相關類  
  5. import android.view.WindowManager;//引入相關類  
  6. //繼承自Activity的引用  
  7. public class Sample_7_1 extends Activity {  
  8.     BallView bv;        //BallView對象引用  
  9.     @Override 
  10.     public void onCreate(Bundle savedInstanceState) {  
  11.         super.onCreate(savedInstanceState);  
  12.         requestWindowFeature(Window.FEATURE_NO_TITLE);      //設置不顯示標題  
  13.         getWindow().setFlags(                                   //設置爲全屏模式  
  14.                 WindowManager.LayoutParams.FLAG_FULLSCREEN,   
  15.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);  
  16.         bv = new BallView(this);    //創建BallView對象  
  17.         setContentView(bv);         //將屏幕設置爲BallView對象  
  18.     }  

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章