游戏编程需要一些经常使用的数学和物理知识,下面演示一下:

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.     }