簡單介紹:
用安卓實現的一個黑色全屏上,紅色的小球的隨機跳動,加速度越來越快。
採用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