【Android】弹跳的小球——SurfaceView

简单介绍:

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

采用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 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.csdn.net/detail/felicitia/5568083

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值