Android小程序-模拟小球平抛落地反弹到静止过程

[size=medium][color=gray]一、开发运动体Movable类
我们将小球视为一个可移动物体Movable对象,该类中除了包含小球图片对象之外,还包括如位置坐标、水平竖直速度等一系列用于模拟小球运动的成员变量和一些方法。具体代码如下:[/color][/size]
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);
}

}

[size=medium][color=gray]二、开发物理引擎BallThread类
该类继承自Thread类,在程序中,每一个Movable对象都会有一个独立的BallThread对象,其主要作用是改变小球的运动轨迹。具体代码如下:[/color][/size]
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();
}
}
}
}

[size=medium][color=gray]三、开发视图BallView类
这次我们介绍的是负责画面渲染的视图类BallView,其中声明了一些物理计算时需要使用静态常量,同时还声明了程序中要绘制的图片资源以及要绘制的小球对象列表。具体代码如下:[/color][/size]
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;
}
}


[size=medium][color=gray]四、开发绘制线程DrawThread类
该类的弄能比较简单,主要是负责定时重绘屏幕和计算帧速率。具体代码如下:[/color][/size]
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();
}
}
}
}

[size=medium][color=gray]五、开发主Activity类
该类用于加载界面组件。具体代码如下:[/color][/size]
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);
}
}

[size=medium][color=gray] 至此整个程序代码开发完毕。该代码可直接运行。[/color][/size]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值