Android应用开发之Android小程序-模拟小球平抛落地反弹到静止过程
白羽 2018-08-10 来源 :网络 阅读 821 评论 0

摘要:本文将带你了解Android应用开发之Android小程序-模拟小球平抛落地反弹到静止过程,希望本文对大家学Android有所帮助

        本文将带你了解Android应用开发之Android小程序-模拟小球平抛落地反弹到静止过程,希望本文对大家学Android有所帮助


一、开发运动体Movable类
   我们将小球视为一个可移动物体Movable对象,该类中除了包含小球图片对象之外,还包括如位置坐标、水平竖直速度等一系列用于模拟小球运动的成员变量和一些方法。具体代码如下:
Java代码  package xiao.fuyan.ball;    import android.graphics.Bitmap;  import android.graphics.Canvas;    /**  * Created by xiao on 2017/2/9.  */  public class Movable {      //初始X,Y坐标      int startX = 0, startY = 0;      //实时X,Y坐标      int x = 0, y = 0;      //初始水平、竖直方向的速度      float startV_X = 0f;      float startV_Y = 0f;      //实时水平、竖直方向的速度      float v_x = 0f;      float v_y = 0f;      //可移动物体半径      int r;      //X,Y方向上运动的时间      double timeX, timeY;      //可移动物体的图片      Bitmap bitmap = null;      //负责小球运动的线程      BallThread bt = null;      //小球是否从木板上落下      boolean bFall = false;      //小球撞地后速度的损失系数      float impactFactor = 0.25f;        //构造器,负责初始化主要的成员变量      public Movable(int x, int y, int r, Bitmap bitmap){          this.startX = x;          this.x = x;          this.startY = y;          this.y = y;          this.r = r;          this.bitmap = bitmap;          //获取系统时间来初始化timeX          this.timeX = System.nanoTime();          this.v_x = BallView.V_MIN + (int)((BallView.V_MAX - BallView.V_MIN)*Math.random());          this.bt = new BallThread(this);          this.bt.start();      }        //将自己绘制到屏幕上      public void drawSelf(Canvas canvas){          canvas.drawBitmap(this.bitmap, x, y, null);      }    }  package xiao.fuyan.ball;

import android.graphics.Bitmap;
import android.graphics.Canvas;

/**
 * Created by xiao on 2017/2/9.
 */
public class Movable {
    //初始X,Y坐标
    int startX = 0, startY = 0;
    //实时X,Y坐标
    int x = 0, y = 0;
    //初始水平、竖直方向的速度
    float startV_X = 0f;
    float startV_Y = 0f;
    //实时水平、竖直方向的速度
    float v_x = 0f;
    float v_y = 0f;
    //可移动物体半径
    int r;
    //X,Y方向上运动的时间
    double timeX, timeY;
    //可移动物体的图片
    Bitmap bitmap = null;
    //负责小球运动的线程
    BallThread bt = null;
    //小球是否从木板上落下
    boolean bFall = false;
    //小球撞地后速度的损失系数
    float impactFactor = 0.25f;

    //构造器,负责初始化主要的成员变量
    public Movable(int x, int y, int r, Bitmap bitmap){
        this.startX = x;
        this.x = x;
        this.startY = y;
        this.y = y;
        this.r = r;
        this.bitmap = bitmap;
        //获取系统时间来初始化timeX
        this.timeX = System.nanoTime();
        this.v_x = BallView.V_MIN + (int)((BallView.V_MAX - BallView.V_MIN)*Math.random());
        this.bt = new BallThread(this);
        this.bt.start();
    }

    //将自己绘制到屏幕上
    public void drawSelf(Canvas canvas){
        canvas.drawBitmap(this.bitmap, x, y, null);
    }

}

二、开发物理引擎BallThread类
   该类继承自Thread类,在程序中,每一个Movable对象都会有一个独立的BallThread对象,其主要作用是改变小球的运动轨迹。具体代码如下:
Java代码  package xiao.fuyan.ball;    /**  * Created by xiao on 2017/2/9.  */  public class BallThread extends Thread {      //Movable对象的引用      Movable father;      //线程执行标志位      boolean flag = false;      //休眠时间      int sleepSpan = 40;      //小球下落的加速度      float g = 200;      //记录当前的时间      double current;        public BallThread(Movable father){          this.father = father;          this.flag = true;      }        @Override      public void run() {          while(flag){              //获取当前时间,单位为纳秒              current = System.nanoTime();                //处理水平方向上的运动,首先获取水平运动的时间              double timeSpanX = (double) ((current - father.timeX)/1000/1000/1000);              //获取水平方向移动的距离              father.x = (int) (father.startX + father.v_x * timeSpanX);                //处理竖直方向上的运动              //判断小球是否移出挡板              if(father.bFall){                  double timeSpanY = (double) ((current - father.timeY)/1000/1000/1000);                  father.y = (int) (father.startY + father.startV_Y * timeSpanY + timeSpanY * timeSpanY * g/2);                  //计算竖直方向速度                  father.v_y = (float) (father.startV_Y + g * timeSpanY);                    //判断小球是否到达最高点                  if(father.startV_Y < 0 && Math.abs(father.v_y) <= BallView.UP_ZERO){                      //设置新的运动阶段竖直方向上的开始时间                      father.timeY = System.nanoTime();                      //设置新的运动阶段竖直方向上的实时速度                      father.v_y = 0;                      //设置新的运动阶段竖直方向上的初始速度                      father.startV_Y = 0;                      //设置新的运动阶段竖直方向上的初始位置                      father.startY = father.y;                  }                    //判断小球是否撞地                  if(father.y + father.r * 2 >= BallView.GROUND_LING && father.v_y > 0){                      //衰减水平和竖直方向的速度                      father.v_x = father.v_x * (1 - father.impactFactor);                      father.v_y = 0 - father.v_y * (1 - father.impactFactor);                        if(Math.abs(father.v_y) < BallView.DOWN_ZERO){ //撞地衰减后速度太小就直接停止                          this.flag = false;                      }else{                          father.startX = father.x;                          father.timeX = System.nanoTime();                            father.startY = father.y;                          father.timeY = System.nanoTime();                          father.startV_Y = father.v_y;                      }                  }                }else if(father.x + father.r/2 >= BallView.WOOD_EDGE){                  father.timeY = System.nanoTime();                  father.bFall = true;              }                try{                  sleep(sleepSpan);              }catch (Exception e){                  e.printStackTrace();              }          }      }  }  package xiao.fuyan.ball;

/**
 * Created by xiao on 2017/2/9.
 */
public class BallThread extends Thread {
    //Movable对象的引用
    Movable father;
    //线程执行标志位
    boolean flag = false;
    //休眠时间
    int sleepSpan = 40;
    //小球下落的加速度
    float g = 200;
    //记录当前的时间
    double current;

    public BallThread(Movable father){
        this.father = father;
        this.flag = true;
    }

    @Override
    public void run() {
        while(flag){
            //获取当前时间,单位为纳秒
            current = System.nanoTime();

            //处理水平方向上的运动,首先获取水平运动的时间
            double timeSpanX = (double) ((current - father.timeX)/1000/1000/1000);
            //获取水平方向移动的距离
            father.x = (int) (father.startX + father.v_x * timeSpanX);

            //处理竖直方向上的运动
            //判断小球是否移出挡板
            if(father.bFall){
                double timeSpanY = (double) ((current - father.timeY)/1000/1000/1000);
                father.y = (int) (father.startY + father.startV_Y * timeSpanY + timeSpanY * timeSpanY * g/2);
                //计算竖直方向速度
                father.v_y = (float) (father.startV_Y + g * timeSpanY);

                //判断小球是否到达最高点
                if(father.startV_Y < 0 && Math.abs(father.v_y) <= BallView.UP_ZERO){
                    //设置新的运动阶段竖直方向上的开始时间
                    father.timeY = System.nanoTime();
                    //设置新的运动阶段竖直方向上的实时速度
                    father.v_y = 0;
                    //设置新的运动阶段竖直方向上的初始速度
                    father.startV_Y = 0;
                    //设置新的运动阶段竖直方向上的初始位置
                    father.startY = father.y;
                }

                //判断小球是否撞地
                if(father.y + father.r * 2 >= BallView.GROUND_LING && father.v_y > 0){
                    //衰减水平和竖直方向的速度
                    father.v_x = father.v_x * (1 - father.impactFactor);
                    father.v_y = 0 - father.v_y * (1 - father.impactFactor);

                    if(Math.abs(father.v_y) < BallView.DOWN_ZERO){ //撞地衰减后速度太小就直接停止
                        this.flag = false;
                    }else{
                        father.startX = father.x;
                        father.timeX = System.nanoTime();

                        father.startY = father.y;
                        father.timeY = System.nanoTime();
                        father.startV_Y = father.v_y;
                    }
                }

            }else if(father.x + father.r/2 >= BallView.WOOD_EDGE){
                father.timeY = System.nanoTime();
                father.bFall = true;
            }

            try{
                sleep(sleepSpan);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
三、开发视图BallView类
   这次我们介绍的是负责画面渲染的视图类BallView,其中声明了一些物理计算时需要使用静态常量,同时还声明了程序中要绘制的图片资源以及要绘制的小球对象列表。具体代码如下:
Java代码  package xiao.fuyan.ball;    import android.content.Context;  import android.content.res.Resources;  import android.graphics.Bitmap;  import android.graphics.BitmapFactory;  import android.graphics.Canvas;  import android.graphics.Color;  import android.graphics.Paint;  import android.view.SurfaceHolder;  import android.view.SurfaceView;    import java.util.ArrayList;  import java.util.Random;    /**  * Created by xiao on 2017/2/9.  */  public class BallView extends SurfaceView implements SurfaceHolder.Callback {        //小球水平速度的最值      public static final int V_MAX = 65;      public static final int V_MIN = 45;      //木板右边沿的X坐标      public static final int WOOD_EDGE = 110;      //游戏中代表地面的坐标,小球到此后会弹起      public static final int GROUND_LING = 1920;      //小球上升时,如果速度小于该值就算0      public static final int UP_ZERO = 30;      //小球撞地时,如果速度小于该值就算0      public static final int DOWN_ZERO = 60;        //各种颜色形状的小球图片的引用      Bitmap[] bitmaps = new Bitmap[6];      //背景图片对象      Bitmap bmpBack;      //木板图片对象      Bitmap bmpWood;      //帧速率字符串      String fps = "FPS:N/A";      //小球数目      int ballNumber = 6;      ArrayList<Movable> alMovable = new ArrayList<Movable>();      //后台屏幕绘制线程      DrawThread dt;        //构造器      public BallView(Context context){          super(context);          getHolder().addCallback(this);          //初始化图片          initBitmaps(getResources());          //初始化小球          initMovables();          //初始化重绘线程          dt = new DrawThread(this, getHolder());        }        //初始化图片      public void initBitmaps(Resources r){          bitmaps[0] = BitmapFactory.decodeResource(r, R.mipmap.red_small);          bitmaps[1] = BitmapFactory.decodeResource(r, R.mipmap.red);          bitmaps[2] = BitmapFactory.decodeResource(r, R.mipmap.yellow_small);          bitmaps[3] = BitmapFactory.decodeResource(r, R.mipmap.yello);          bitmaps[4] = BitmapFactory.decodeResource(r, R.mipmap.blue_small);          bitmaps[5] = BitmapFactory.decodeResource(r, R.mipmap.blue);          bmpBack = BitmapFactory.decodeResource(r, R.mipmap.wall);          bmpWood = BitmapFactory.decodeResource(r, R.mipmap.wood);      }        public void initMovables(){          Random r = new Random();          for(int i = 0; i < ballNumber; i++){              int index = r.nextInt(32);              Bitmap tmp = null;              if(i < ballNumber/2){                  tmp = bitmaps[3 + index % 3];              }else{                  tmp = bitmaps[index % 3];              }                //创建Movable对象              Movable m = new Movable(0, 110 - tmp.getHeight(), tmp.getWidth()/2, tmp);              alMovable.add(m);          }      }        public void doDraw(Canvas canvas){          canvas.drawBitmap(bmpBack, 0, 0, null);          canvas.drawBitmap(bmpWood, 0, 100, null);          for(Movable m : alMovable){              m.drawSelf(canvas);          }            Paint p = new Paint();          p.setColor(Color.BLUE);          p.setTextSize(60);          p.setAntiAlias(true);          canvas.drawText(fps, 800, 80, p);      }        @Override      public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {        }        @Override      public void surfaceCreated(SurfaceHolder holder) {          if(!dt.isAlive()){              dt.start();          }      }        @Override      public void surfaceDestroyed(SurfaceHolder holder) {          dt.flag = false;          dt = null;      }  }  package xiao.fuyan.ball;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.util.ArrayList;
import java.util.Random;

/**
 * Created by xiao on 2017/2/9.
 */
public class BallView extends SurfaceView implements SurfaceHolder.Callback {

    //小球水平速度的最值
    public static final int V_MAX = 65;
    public static final int V_MIN = 45;
    //木板右边沿的X坐标
    public static final int WOOD_EDGE = 110;
    //游戏中代表地面的坐标,小球到此后会弹起
    public static final int GROUND_LING = 1920;
    //小球上升时,如果速度小于该值就算0
    public static final int UP_ZERO = 30;
    //小球撞地时,如果速度小于该值就算0
    public static final int DOWN_ZERO = 60;

    //各种颜色形状的小球图片的引用
    Bitmap[] bitmaps = new Bitmap[6];
    //背景图片对象
    Bitmap bmpBack;
    //木板图片对象
    Bitmap bmpWood;
    //帧速率字符串
    String fps = "FPS:N/A";
    //小球数目
    int ballNumber = 6;
    ArrayList<Movable> alMovable = new ArrayList<Movable>();
    //后台屏幕绘制线程
    DrawThread dt;

    //构造器
    public BallView(Context context){
        super(context);
        getHolder().addCallback(this);
        //初始化图片
        initBitmaps(getResources());
        //初始化小球
        initMovables();
        //初始化重绘线程
        dt = new DrawThread(this, getHolder());

    }

    //初始化图片
    public void initBitmaps(Resources r){
        bitmaps[0] = BitmapFactory.decodeResource(r, R.mipmap.red_small);
        bitmaps[1] = BitmapFactory.decodeResource(r, R.mipmap.red);
        bitmaps[2] = BitmapFactory.decodeResource(r, R.mipmap.yellow_small);
        bitmaps[3] = BitmapFactory.decodeResource(r, R.mipmap.yello);
        bitmaps[4] = BitmapFactory.decodeResource(r, R.mipmap.blue_small);
        bitmaps[5] = BitmapFactory.decodeResource(r, R.mipmap.blue);
        bmpBack = BitmapFactory.decodeResource(r, R.mipmap.wall);
        bmpWood = BitmapFactory.decodeResource(r, R.mipmap.wood);
    }

    public void initMovables(){
        Random r = new Random();
        for(int i = 0; i < ballNumber; i++){
            int index = r.nextInt(32);
            Bitmap tmp = null;
            if(i < ballNumber/2){
                tmp = bitmaps[3 + index % 3];
            }else{
                tmp = bitmaps[index % 3];
            }

            //创建Movable对象
            Movable m = new Movable(0, 110 - tmp.getHeight(), tmp.getWidth()/2, tmp);
            alMovable.add(m);
        }
    }

    public void doDraw(Canvas canvas){
        canvas.drawBitmap(bmpBack, 0, 0, null);
        canvas.drawBitmap(bmpWood, 0, 100, null);
        for(Movable m : alMovable){
            m.drawSelf(canvas);
        }

        Paint p = new Paint();
        p.setColor(Color.BLUE);
        p.setTextSize(60);
        p.setAntiAlias(true);
        canvas.drawText(fps, 800, 80, p);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if(!dt.isAlive()){
            dt.start();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        dt.flag = false;
        dt = null;
    }
}


四、开发绘制线程DrawThread类
   该类的弄能比较简单,主要是负责定时重绘屏幕和计算帧速率。具体代码如下:
Java代码  package xiao.fuyan.ball;    import android.graphics.Canvas;  import android.view.SurfaceHolder;    /**  * Created by xiao on 2017/2/9.  */  public class DrawThread extends Thread {      //BallView对象的引用      BallView bv;      //SurfaceHolder对象的引用      SurfaceHolder surfaceHolder;      //线程执行标志位      boolean flag = false;      //休眠时间      int sleepSpan;      //记录开始时刻,用于计算帧速率      long start = System.nanoTime();      //记录帧数      int count = 0;        public DrawThread(BallView bv, SurfaceHolder surfaceHolder){          this.bv = bv;          this.surfaceHolder = surfaceHolder;          this.flag = true;      }        @Override      public void run() {          Canvas canvas = null;            while(flag){              try {                  //获取BallView的画布                  canvas = surfaceHolder.lockCanvas(null);                  synchronized (surfaceHolder){                      bv.doDraw(canvas);                  }              }catch (Exception e){                  e.printStackTrace();              }finally {                  if(canvas != null){                      surfaceHolder.unlockCanvasAndPost(canvas);                  }              }              count++;              if(count == 20){                  count = 0;                  long tempStamp = System.nanoTime();                  long span = tempStamp - start;                  start = tempStamp;                  double fps = Math.round(100000000000.0/span*20)/100.0;                    bv.fps = "FPS:" + fps;              }              try{                  sleep(sleepSpan);              }catch (Exception e){                  e.printStackTrace();              }          }      }  }  package xiao.fuyan.ball;

import android.graphics.Canvas;
import android.view.SurfaceHolder;

/**
 * Created by xiao on 2017/2/9.
 */
public class DrawThread extends Thread {
    //BallView对象的引用
    BallView bv;
    //SurfaceHolder对象的引用
    SurfaceHolder surfaceHolder;
    //线程执行标志位
    boolean flag = false;
    //休眠时间
    int sleepSpan;
    //记录开始时刻,用于计算帧速率
    long start = System.nanoTime();
    //记录帧数
    int count = 0;

    public DrawThread(BallView bv, SurfaceHolder surfaceHolder){
        this.bv = bv;
        this.surfaceHolder = surfaceHolder;
        this.flag = true;
    }

    @Override
    public void run() {
        Canvas canvas = null;

        while(flag){
            try {
                //获取BallView的画布
                canvas = surfaceHolder.lockCanvas(null);
                synchronized (surfaceHolder){
                    bv.doDraw(canvas);
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                if(canvas != null){
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
            count++;
            if(count == 20){
                count = 0;
                long tempStamp = System.nanoTime();
                long span = tempStamp - start;
                start = tempStamp;
                double fps = Math.round(100000000000.0/span*20)/100.0;

                bv.fps = "FPS:" + fps;
            }
            try{
                sleep(sleepSpan);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}

五、开发主Activity类
   该类用于加载界面组件。具体代码如下:
Java代码  package xiao.fuyan.ball;    import android.app.Activity;  import android.os.Bundle;  import android.view.Window;  import android.view.WindowManager;      public class MainActivity extends Activity {      BallView bv;        @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          //设置不显示标题          requestWindowFeature(Window.FEATURE_NO_TITLE);          getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,                  WindowManager.LayoutParams.FLAG_FULLSCREEN);            bv = new BallView(this);          setContentView(bv);      }  }  package xiao.fuyan.ball;

import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;


public class MainActivity extends Activity {
    BallView bv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置不显示标题
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        bv = new BallView(this);
        setContentView(bv);
    }
}

   至此整个程序代码开发完毕。该代码可直接运行。    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程