【Android】弹跳的小球——SurfaceView

来源:互联网 发布:大数据分析模型 编辑:程序博客网 时间:2024/04/29 03:39

简单介绍:

用安卓实现的一个黑色全屏上,红色的小球的随机跳动,加速度越来越快。

采用surfaceview实现,在activity中设置为全屏,并将小球弹跳的surfaceview设置为显示的view,主要代码都在surfaceview中实现。


将小球的初始位置设置为屏幕的中央,将初始的方向设置为向下(用角度表示,右方向为0°,顺时针方向角度增加),加速度设置为1。然后开启线程进行surfaceview的重绘,线程Thread.sleep(10)之后进行一次重绘,并且加速度加0.2,否则太快。每次重绘时判断是否碰壁,写了一个static final的类来记录碰了哪边的壁,然后对弹跳方向进行180°之内(因为不能方向是弹出屏幕的)的随机,不随机的话路线会固定,所以随机。


主要代码:

public class GameView extends SurfaceView implements Callback{private float x;private float y;private double angle;//右方向为正方向,角度为零,顺时针private int radius;private SurfaceHolder surfaceHolder;private AnimThread thread;private double accelerate;private int lastDir = Direction.MID;public GameView(Context context) {super(context);// TODO Auto-generated constructor stubsurfaceHolder = this.getHolder();surfaceHolder.addCallback(this);this.setFocusable(true);thread = new AnimThread(surfaceHolder, getContext());}@Overridepublic void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {// TODO Auto-generated method stub}@Overridepublic void surfaceCreated(SurfaceHolder arg0) {// TODO Auto-generated method stubx = getWidth()/2;y = getHeight()/2;radius = 30;angle = Math.PI*0.5;accelerate = 1;thread.isRunning = true;thread.start();}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// TODO Auto-generated method stubthread.isRunning = false;try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}}public void drawCircle(Canvas canvas, Paint paint) {canvas.drawColor(Color.BLACK); // 清空屏幕canvas.drawCircle(x, y, radius, paint);y += Math.sin(angle)*accelerate;x += Math.cos(angle)*accelerate;switch(getDirection(x,y)){case Direction.UP:angle = Math.random()*Math.PI;break;case Direction.DOWN:angle = (1+Math.random())*Math.PI;break;case Direction.LEFT:angle = (Math.random()-0.5)*Math.PI;break;case Direction.RIGHT:angle = (0.5+Math.random())*Math.PI;break;}}public int getDirection(float x, float y){if(y<=radius && lastDir!=Direction.UP){lastDir = Direction.UP;y = radius;Log.i("dir", "up");return Direction.UP;}else if(y>=(getHeight()-radius) && lastDir!=Direction.DOWN){lastDir = Direction.DOWN;y = getHeight()-radius;Log.i("dir","down");return Direction.DOWN;}else if(x<=radius && lastDir!=Direction.LEFT){lastDir = Direction.LEFT;x = radius;Log.i("dir","left");return Direction.LEFT;}else if(x>=getWidth()-radius && lastDir!=Direction.RIGHT){lastDir = Direction.RIGHT;x = getWidth()-radius;Log.i("dir","right");return Direction.RIGHT;}return Direction.MID;}static final class Direction{public static final  int LEFT = 0;public static final  int RIGHT = 1;public static final  int UP = 2;public static final  int DOWN = 3;public static final int MID = 4;}class AnimThread extends Thread implements Runnable {private boolean isRunning;private SurfaceHolder holder;private Context context;private Paint paint;public AnimThread(SurfaceHolder holder , Context context) {this.holder = holder;this.context = context;isRunning = false;paint = new Paint();paint.setColor(Color.RED);paint.setStyle(Paint.Style.FILL);}public void run() { // 计算绘制动画的坐标Canvas canvas = null;while(isRunning){accelerate += 0.2;canvas = holder.lockCanvas(null);drawCircle(canvas, paint);try {Thread.sleep(10);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}finally{holder.unlockCanvasAndPost(canvas);}}}}}

遇到的问题:

1.      之前考虑加速度没有头绪,后来根据需求采用加速度,方向的角度来进行绘制,因为当角度知道了,有了距离,x,y方向移动的距离也可以知道,并且角度定义之后sin,cos值都有正负,也无需自己考虑,实现起来很简单。需要说明的是,其实上文中一直使用的加速度,就是在当前方向上移动的距离。

2.      判断碰到左壁的时候发现是0到π/2和3/2π到2π,加了判断表示比较麻烦,后来发现直接表示成-π/2到π/2即可。

小球碰壁之后方向刚一改变就又发生改变很奇怪,通过log输出发现在碰壁后的下一次绘制的判断中可能又会判断为碰这个壁,所以又会随机一次方向,造成方向的改变,故增加了变量了记录上一次的碰壁,因为不可能连续碰两次相同的壁,所以增加判断,如果碰的壁和上次不是一个才进行方向的改变即可。

工程地址

http://download.csdn.net/detail/felicitia/5568083

原创粉丝点击