简单介绍:
用安卓实现的一个黑色全屏上,红色的小球的随机跳动,加速度越来越快。
采用surfaceview实现,在activity中设置为全屏,并将小球弹跳的surfaceview设置为显示的view,主要代码都在surfaceview中实现。
主要代码:
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 stub
surfaceHolder = this.getHolder();
surfaceHolder.addCallback(this);
this.setFocusable(true);
thread = new AnimThread(surfaceHolder, getContext());
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
x = getWidth()/2;
y = getHeight()/2;
radius = 30;
angle = Math.PI*0.5;
accelerate = 1;
thread.isRunning = true;
thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.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 block
e.printStackTrace();
}finally{
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
遇到的问题:
1. 之前考虑加速度没有头绪,后来根据需求采用加速度,方向的角度来进行绘制,因为当角度知道了,有了距离,x,y方向移动的距离也可以知道,并且角度定义之后sin,cos值都有正负,也无需自己考虑,实现起来很简单。需要说明的是,其实上文中一直使用的加速度,就是在当前方向上移动的距离。
2. 判断碰到左壁的时候发现是0到π/2和3/2π到2π,加了判断表示比较麻烦,后来发现直接表示成-π/2到π/2即可。
小球碰壁之后方向刚一改变就又发生改变很奇怪,通过log输出发现在碰壁后的下一次绘制的判断中可能又会判断为碰这个壁,所以又会随机一次方向,造成方向的改变,故增加了变量了记录上一次的碰壁,因为不可能连续碰两次相同的壁,所以增加判断,如果碰的壁和上次不是一个才进行方向的改变即可。工程地址
http://download.youkuaiyun.com/detail/felicitia/5568083