之前已经能产生许多小球,但是会发现小球和小球接触后,其中一个球的形状就消失了一部分,没有起到碰撞的效果,所以接下来就继续完成操作。
考虑到碰撞情况,无法就是考虑两球球心间距离与它们半径之和的比较关系,前者小于后者就发生碰撞,反之则没有发生。当然如果只有一个球,自然不会发生碰撞的哈!
//分析碰撞情况
for(int i=0;i<al.size();i++)
{
Ball ball=al.get(i);//获取小球
if(ball==this)
{
continue;//重新开始循环,考虑下一个球
}
int xx=Math.abs((x+radius)-(ball.x+ball.radius));//两个球心所在纵线的距离
int yy=Math.abs((y-radius)-(ball.y-ball.radius));//两个球心所在水平线的距离
int len=(int)Math.sqrt(xx*xx+yy*yy);//球心之间的距离
if(len<radius+ball.radius)
{
int temp=vx;
vx=ball.vx;
ball.vx=temp;
int temp1=vy;
vy=ball.vy;
ball.vy=temp1;
}
}
这样就能实现小球碰撞的效果,只是还想球能够停止,然后又能动起来,或者是沿着窗体滚动,怎样弄呢?
不妨设置三个标记,分别是暂停,停止,绕行标记,当符合标记,则按相应标记进行。此外补充说明,在测试类中要创建一个ArrayList类对象,保存所有出现的球,然后就可以随意地取出。
下面是改进后的球的线程类代码;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class Ball extends Thread{
private int x,y;//小球所在最小正方形的左上角坐标
private int vx,vy;//小球的各分向速度
private int radius;//小球的半径
private Color color;
private JPanel jpa;//画布所在面板
private ArrayList<Ball>al;//存储球的队列
private boolean PauseFlag;//暂停标志
private boolean StopFlag;//停止标志
private boolean RoundFlag;
/
private static final int FORWARD = 0;
private static final int BACKWARD = 1;
private static final int DOWN = 2;
private static final int UP = 3;
private int direction = FORWARD;
//构造函数,传入放置画布的面板和存储所有球队列,而且设置球的参数
public Ball(JPanel jpa,ArrayList al)
{
this.jpa=jpa;
this.al=al;
Random rad=new Random();
vx=rad.nextInt(20)+2;
vy=rad.nextInt(25)+3;
radius=rad.nextInt(30)+10;
color=new Color(rad.nextInt(256),rad.nextInt(256),rad.nextInt(256));
}
//添加暂停的方法
public void setPause(boolean flag)
{
PauseFlag=flag;
}
//添加环绕的方法
public void setRound(boolean flag)
{
RoundFlag=flag;
}
public void run()
{
Graphics g=jpa.getGraphics();//获取画布
while(true)
{
try{
Thread.sleep(50);
}catch(InterruptedException e)
{
e.printStackTrace();
}
//如果暂停标志为true,则循环在此处结尾,从头重新开始
if(PauseFlag)
{
continue;
}
//清屏操作
g.setColor(jpa.getBackground());
g.fillOval(x, y, radius*2, radius*2);
if(RoundFlag)
{
if (x+radius*2>jpa.getWidth() && direction == FORWARD)
direction = DOWN;
if (y+radius*2>jpa.getHeight() && direction == DOWN)
direction = BACKWARD;
if (x - radius * 2 <= 10 && direction == BACKWARD)
direction = UP;
if (y -radius*2 <=10&& direction == UP)
direction = FORWARD;
// compute angle start & extent
if (direction == FORWARD) {
x += 1;
y = 0;
}
if (direction == DOWN) {
x = jpa.getWidth() - 2*radius;
y += 1;
}
if (direction == BACKWARD) {
x -= 1;
y = jpa.getHeight() - radius * 2+1;
}
if (direction == UP) {
x = 0;
y -= 1;
}
}
//如果重置标志为true,则跳出循环
if(StopFlag)
{
return;
}
//分析碰撞情况
for(int i=0;i<al.size();i++)
{
Ball ball=al.get(i);//获取小球
if(ball==this)
{
continue;//重新开始循环,考虑下一个球
}
int xx=Math.abs((x+radius)-(ball.x+ball.radius));//两个球心所在纵线的距离
int yy=Math.abs((y-radius)-(ball.y-ball.radius));//两个球心所在水平线的距离
int len=(int)Math.sqrt(xx*xx+yy*yy);//球心之间的距离
if(len<radius+ball.radius)
{
int temp=vx;
vx=ball.vx;
ball.vx=temp;
int temp1=vy;
vy=ball.vy;
ball.vy=temp1;
}
}
//更改坐标情况
x+=vx;
y+=vy;
//小球出界反弹
if(x+radius*2>jpa.getWidth()||x<0)
{
vx=vx*(-1);
}
if(y+radius*2>jpa.getHeight()||y<0)
{
vy=vy*(-1);
}
g.setColor(color);
g.fillOval(x, y, 2*radius, 2*radius);
}
}
}
然后是主界面类:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BallJFrame {
/**
* @param args
*/
public static void main(String[] args) {
BallJFrame bj=new BallJFrame();
bj.init();
}
public void init()
{
final JFrame jf=new JFrame();
jf.setTitle("小球碰撞");
jf.setSize(500, 500);
jf.setDefaultCloseOperation(3);
jf.setLayout(new BorderLayout());
jf.setResizable(false);
final ArrayList<Ball> arraylist=new ArrayList<Ball>();
final JPanel jpa=new JPanel();
jpa.setBounds(0,30,500,450);
jpa.setBackground(Color.BLACK);//设置面板背景色为黑色
jf.add(jpa,BorderLayout.CENTER);
ActionListener al=new ActionListener(){
public void actionPerformed(ActionEvent e) {
String str=e.getActionCommand();
if(str.equals("Add"))
{
Ball ball=new Ball(jpa,arraylist);
ball.start();
arraylist.add(ball);
}
if(str.equals("Stop"))
{
for(int i=0;i<arraylist.size();i++)
{
Ball ball=arraylist.get(i);
ball.setPause(true);
}
}
if(str.equals("Resume"))
{
for(int i=0;i<arraylist.size();i++)
{
Ball ball=arraylist.get(i);
ball.setPause(false);
}
}
if(str.equals("Round"))
{
for(int i=0;i<arraylist.size();i++)
{
Ball ball=arraylist.get(i);
ball.setRound(true);
}
}
}
};
JPanel jpa2=new JPanel(new FlowLayout());
jpa2.setBounds(0,0,500,80);
JButton jbu_add=new JButton("Add");
jbu_add.addActionListener(al);
jpa2.add(jbu_add);
JButton jbu_stop=new JButton("Stop");
jbu_stop.addActionListener(al);
jpa2.add(jbu_stop);
JButton jbu_resume=new JButton("Resume");
jbu_resume.addActionListener(al);
jpa2.add(jbu_resume);
JButton jbu_round=new JButton("Round");
jbu_round.addActionListener(al);
jpa2.add(jbu_round);
jf.add(jpa2,BorderLayout.NORTH);
jf.setVisible(true);
}
}
这样就既能实现小球碰撞的效果,然后又能让它们暂停,重新动起来,或者绕着滚·····你可以尝试弄出更多的效果,继而超越屏保的视觉效果!