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 (); // reclaim the image
}
Private class PaintThread extends Thread
{
Private SurfaceHolder holder; // drawing control class
Private Paint paint; // Paint brush
Private float [] [] bils = new float [20] [2]; // used to save the coordinates of 20 balls
Private int [] direction = new int [20]; // used to save the direction of each ball
Private int radius = 20; // the radius of the ball
Public boolean isRun = true; // whether the program is running
Private int ballStep = 20; // The length of each ball.
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 ++) // initialize the direction of each ball
{
Direction [I] = random. nextInt (4 );
}
Music = new MediaPlayer ();
File file = new File (Environment. getExternalStorageDirectory (), "flower.pdf ");
Try {
Music. reset ();
Music. setDataSource (file. getAbsolutePath ());
Music. prepare ();
Music. setLooping (true); // loop playback
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 ()
{
Initbils (); // initialize the position of each ball
While (isRun)
{
Draw (); // draw each ball
Logic (); // calculate the position of each ball
}
}
Private void initbils (){
// TODO Auto-generated method stub
Random random = new Random ();
For (int I = 0; I <bils. length; I ++) // initialize the position of each ball
{
Boolean order = true; // cyclically generates the Coordinate Position of a ball until the position is reasonable.
While (order)
{
// Pay attention to the position of the ball
Bils [I] [0] = radius + (float) random. nextInt (BallsView. this. getWidth ()-2 * radius); // abscissa
Bils [I] [1] = radius + (float) random. nextInt (BallsView. this. getHeight ()-2 * radius); // y coordinate
Boolean isCollapse = isCollapse (I, bils [I] [0], bils [I] [1]); // determines whether the ball will collide with other balls
// Here it should be compared with the produced ball, but it is unreasonable to compare it with all the balls.
If (isCollapse = false)
Order = false; // The initial position is reasonable and no random position of the ball is generated.
}
}
}
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); // draw the background to overwrite the original interface.
Canvas. drawBitmap (bitmap, 0, 0, paint );
For (int I = 0; I <20; I ++)
{
Canvas. drawCircle (bils [I] [0], bils [I] [1], radius, paint); // display the position of each ball
}
Holder. unlockCanvasAndPost (canvas );
}
}
/**
* Logic of every ball walk
*/
Public void logic ()
{
Random random = new Random ();
// I indicates the first few balls
For (int I = 0; I <bils. length; I ++)
{
// Random direction of each ball. // 0 indicates left. // 1 indicates right. // 2 indicates top. // 3 indicates bottom.
// Determine the direction of the ball
Boolean isSuccess = false;
Switch (direction [I])
{
Case 0: // left
IsSuccess = goLeft (I );
If (isSuccess = false) // An error occurred while leaving
{
IsSuccess = goRight (I); // right
If (isSuccess)
{Direction [I] = 1 ;}// the operation is successful. Modify the direction.
Else {direction [I] = random. nextInt (2) + 2;} // both the left and right sides fail, changing the upper and lower directions
}
Break;
Case 1: // right
IsSuccess = goRight (I );
If (isSuccess = false) // The right side fails.
{
IsSuccess = goLeft (I); // left
If (isSuccess)
{Direction [I] = 0;} // The operation is successful. Modify the direction.
Else {direction [I] = random. nextInt (2) + 2;} // both the left and right sides fail, changing the upper and lower directions
}
Break;
Case 2: // go up
IsSuccess = goUp (I );
If (isSuccess = false) // failed to go up,
{
IsSuccess = goDown (I); // go down
If (isSuccess)
{Direction [I] = 3;} // The operation is successful. Modify the direction.
Else {direction [I] = random. nextInt (2);} // both upper and lower failed, change direction
}
Break;
Case 3: // go down
IsSuccess = goDown (I );
If (isSuccess = false) // failed to go down,
{
IsSuccess = goUp (I); // go up
If (isSuccess)
{Direction [I] = 2;} // The operation is successful. Modify the direction.
Else {direction [I] = random. nextInt (2);} // both upper and lower failed, change direction
}
Break;
}
}
}
/**
* Logic of the I-th ball going up
* @ Param I the number of the ball
* @ Return false indicates that the walking fails, including hitting the wall and hitting the ball. true indicates that the walking is successful.
*/
Private boolean goUp (int I)
{
// TODO Auto-generated method stub
If (bils [I] [1]-radius <= 0) // the top is the upper boundary.
{Return false ;}
Else
{
Boolean isBallUp = isCollapse (I, bils [I] [0], bils [I] [1]-ballStep); // determines whether the ball will collide with other balls
If (isBallUp = false) // no collision
{
Bils [I] [1]-= ballStep;
Return true;
}
Return false;
}
}
/**
* Logic of the I-th ball going down
* @ Param I the number of the ball
* @ Return false indicates that the walking fails, including hitting the wall and hitting the ball. true indicates that the walking is successful.
*/
Private boolean goDown (int I)
{
If (bils [I] [1]> = BallsView. this. getHeight ()-radius) // The bottom of the border is
Return false;
Else
{
Boolean isBallDown = isCollapse (I, bils [I] [0], bils [I] [1] + ballStep); // determines whether the ball will collide with other balls
If (isBallDown = false) // The result does not hit the ball.
{
Bils [I] [1] + = ballStep;
Return true;
}
Return false;
}
}
/**
* Logic of the I-th ball to the right
* @ Param I the number of the ball
* @ Return false indicates that the walking fails, including hitting the wall and hitting the ball. true indicates that the walking is successful.
*/
Private boolean goRight (int I)
{
If (bils [I] [0]> = BallsView. this. getWidth ()-radius) // right side of the border
Return false; // a boundary collision occurs.
Else
{
Boolean isBallRight = isCollapse (I, bils [I] [0] + ballStep, bils [I] [1]); // determines whether the ball will collide with other balls
If (isBallRight = false) // The result is not hitting the ball.
{
Bils [I] [0] + = ballStep;
Return true;
}
Return false; // collision
}
}
/**
* Logic of the I-th ball to the left
* @ Param I the number of the ball
* @ Return false indicates that the walking fails, including hitting the wall and hitting the ball. true indicates that the walking is successful.
*/
Private boolean goLeft (int I)
{
If (bils [I] [0]-radius <0) // The left side is the border.
Return false;
Else
{// Go to the left
Boolean isBallLeft = isCollapse (I, bils [I] [0]-ballStep, bils [I] [1]); // determines whether the ball will collide with other balls
If (isBallLeft = false) // The result does not hit the ball.
{
Bils [I] [0]-= ballStep;
Return true;
}
Return false;
}
}
/**
* Determine if the I-th ball will collide with other balls
* @ Param I the number of the ball
* @ Param x horizontal coordinates of the ball
* @ Param y the ordinate of the ball
* @ Return returns true to indicate that a collision will occur, and returns false to indicate that a collision will not occur.
*/
Private boolean isCollapse (int I, float x, float y ){
// TODO Auto-generated method stub
For (int j = 0; j <bils. length; j ++) // determines whether a ball exists on the top.
{
If (I! = J)
{
Boolean result = this. isCollapsing (bils [j] [0], x, bils [j] [1], y); // determines whether the two balls are in conflict.
If (result = true) // The result hits the ball.
{
Return true;
}
}
}
Return false;
}
/**
* Determine whether two balls will collide
* @ Param x1 the abscissa of the first ball
* @ Param x2 the abscissa of the second ball
* @ Param y1 the ordinate of the first ball
* @ Param y2 the ordinate of the second ball
* @ 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;
}
}
}
This article from "android games" blog, please be sure to keep this source http://chenshuidewoniu.blog.51cto.com/3622711/1299851