package com.junling.surfaceView;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Environment;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
public class BallsView extends SurfaceView implements Callback{
private SurfaceHolder holder;
private PaintThread thread;
private Context context;
public BallsView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.holder=this.getHolder();
holder.addCallback(this);
thread=new PaintThread(holder,context);
this.context=context;
//this.setBackgroundDrawable(this.getResources().getDrawable(R.drawable.e));
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.start();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
thread.isRun=false;
thread.music.release();
thread.music=null;
thread.bitmap.recycle();//回收图片
}
private class PaintThread extends Thread
{
private SurfaceHolder holder;//绘图控制类
private Paint paint;//画笔
private float[][] balls=new float[20][2];//用于保存20个小球的坐标
private int [] direction=new int[20];//用于保存每个球的方向
private int radius=20;//小球的半径
public boolean isRun=true;//程序是否运行
private int ballStep=20;//每个小球走的步伐长度
public MediaPlayer music;
public Bitmap bitmap=BitmapFactory.decodeResource(getResources(), R.drawable.bg);
public PaintThread(SurfaceHolder holder,Context context) {
this.holder=holder;
paint=new Paint();
Random random=new Random();
for(int i=0;i<20;i++)//为每个小球初始化方向
{
direction[i]=random.nextInt(4);
}
music=new MediaPlayer();
File file=new File(Environment.getExternalStorageDirectory(),"flower.mp3");
try {
music.reset();
music.setDataSource(file.getAbsolutePath());
music.prepare();
music.setLooping(true);//循环播放
music.setOnPreparedListener(new OnPreparedListener(){
@Override
public void onPrepared(MediaPlayer mp) {
// TODO Auto-generated method stub
music.start();
}
});
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run()
{
initBalls(); //初始化每个小球的位置
while(isRun)
{
draw();//绘出每个小球
logic();//计算每个小球的位置
}
}
private void initBalls() {
// TODO Auto-generated method stub
Random random=new Random();
for(int i=0;i<balls.length;i++)//初始化每个小球的位置
{
boolean order=true;//循环产生一个小球的坐标位置,直到该位置合理位置
while(order)
{
//注意小球的位置
balls[i][0]=radius+(float)random.nextInt(BallsView.this.getWidth()-2*radius);//横坐标
balls[i][1]=radius+(float)random.nextInt(BallsView.this.getHeight()-2*radius);//纵坐标
boolean isCollapse=isCollapse(i,balls[i][0],balls[i][1]);//判断该球是否会和其他球相撞
//,这里应该是让它和已经产生的小球进行比较,但是此处是和所有的小球比较有些不合理
if(isCollapse==false)
order=false;//该初始位置是合理的,不用再产生该小球的随机位置
}
}
}
private void draw() {
Canvas canvas=null;
paint.setColor(Color.RED);
if(holder!=null)
{
// TODO Auto-generated method stub
canvas=holder.lockCanvas();
canvas.drawColor(Color.BLACK);//画出背景覆盖原来的界面
canvas.drawBitmap(bitmap, 0, 0, paint);
for(int i=0;i<20;i++)
{
canvas.drawCircle(balls[i][0], balls[i][1], radius, paint);//显示每个小球 的位置
}
holder.unlockCanvasAndPost(canvas);
}
}
/**
* 每个球行走的逻辑
*/
public void logic()
{
Random random=new Random();
//i代表第几个小球
for(int i=0;i<balls.length;i++)
{
//随机每个小球走的方向//0代表左//1代表右//2代表上//3代表下
//判断小球的走向
boolean isSuccess=false;
switch(direction[i])
{
case 0://左走
isSuccess=goLeft(i);
if(isSuccess==false)//左走失败
{
isSuccess=goRight(i);//向右走
if(isSuccess)
{ direction[i]=1;}//走动成功,修改方向
else {direction[i]=random.nextInt(2)+2;}//左右均失败,换上下方向
}
break;
case 1://右走
isSuccess=goRight(i);
if(isSuccess==false)//右走失败
{
isSuccess=goLeft(i);//向左走
if(isSuccess)
{direction[i]=0;}//走动成功,修改方向
else{direction[i]=random.nextInt(2)+2;}//左右均失败,换上下方向
}
break;
case 2://上走
isSuccess=goUp(i);
if(isSuccess==false)//上走失败,
{
isSuccess=goDown(i);//向下走
if(isSuccess)
{direction[i]=3;}//走动成功,修改方向
else{direction[i]=random.nextInt(2);}//上下均失败,换方向
}
break;
case 3://下走
isSuccess=goDown(i);
if(isSuccess==false)//下走失败,
{
isSuccess=goUp(i);//向上走
if(isSuccess)
{direction[i]=2;}//走动成功,修改方向
else{direction[i]=random.nextInt(2);}//上下均失败,换方向
}
break;
}
}
}
/**
* 第i个球向上走的逻辑
* @param i 球的编号
* @return 返回false代表行走失败(包括撞壁和撞球),true代表行走成功
*/
private boolean goUp(int i)
{
// TODO Auto-generated method stub
if(balls[i][1]-radius<=0)//上边是上边界
{ return false;}
else
{
boolean isBallUp=isCollapse(i,balls[i][0],balls[i][1]-ballStep);//判断该球是否会和其他球相撞
if(isBallUp==false)//没有相撞
{
balls[i][1]-=ballStep;
return true;
}
return false;
}
}
/**
* 第i个球向下走的逻辑
* @param i 球的编号
* @return 返回false代表行走失败(包括撞壁和撞球),true代表行走成功
*/
private boolean goDown(int i)
{
if(balls[i][1]>=BallsView.this.getHeight()-radius)//下边是下边界
return false;
else
{
boolean isBallDown=isCollapse(i,balls[i][0],balls[i][1]+ballStep);//判断该球是否会和其他球相撞
if(isBallDown==false)//结果没有撞球
{
balls[i][1]+=ballStep;
return true;
}
return false;
}
}
/**
* 第i个球向右走的逻辑
* @param i 球的编号
* @return 返回false代表行走失败(包括撞壁和撞球),true代表行走成功
*/
private boolean goRight(int i)
{
if(balls[i][0]>=BallsView.this.getWidth()-radius)//右边是右边界
return false;//发生边界碰撞
else
{
boolean isBallRight=isCollapse(i,balls[i][0]+ballStep,balls[i][1]);//判断该球是否会和其他球相撞
if(isBallRight==false)//结果没有撞球
{
balls[i][0]+=ballStep;
return true;
}
return false;//发生碰撞
}
}
/**
* 第i个球向左走的逻辑
* @param i 球的编号
* @return 返回false代表行走失败(包括撞壁和撞球),true代表行走成功
*/
private boolean goLeft(int i)
{
if(balls[i][0]-radius<0)//左边是边界
return false;
else
{ //左边可以走
boolean isBallLeft=isCollapse(i,balls[i][0]-ballStep,balls[i][1]);//判断该球是否会和其他球相撞
if(isBallLeft==false)//结果没有撞球
{
balls[i][0]-=ballStep;
return true;
}
return false;
}
}
/**
* 判断第i个球是否会和其余的球相撞
* @param i 球的编号
* @param x 球的横坐标
* @param y 球的纵坐标
* @return 返回true代表会相撞,返回false代表不会相撞
*/
private boolean isCollapse(int i,float x, float y) {
// TODO Auto-generated method stub
for(int j=0;j<balls.length;j++)//判断上边是否有小球
{
if(i!=j)
{
boolean result=this.isCollapsing(balls[j][0], x, balls[j][1], y);//判断两球是否相撞
if(result==true)//结果撞球
{
return true;
}
}
}
return false;
}
/**
* 判断两个小球是否会相撞
* @param x1 第一个小球的横坐标
* @param x2 第二个小球的横坐标
* @param y1 第一个小球的纵坐标
* @param y2 第二个小球的纵坐标
* @return
*/
private boolean isCollapsing(float x1,float x2,float y1,float y2)
{
if((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)<=(2*radius)*(2*radius))
return true;
return false;
}
}
}
转载于:https://blog.51cto.com/chenshuidewoniu/1299851