上次已经完成了弹球碰壁问题,还没有发表,今天刚刚完成了弹球之间的碰撞。下面我来分析一下的弹球程序。
声明两个按钮,声明一个静态变量,m用来记录按钮的值
JButton a,b; static int m=0;
创建一个队列,装入弹球的线程
public static java.util.ArrayList<Tan> arr=new java.util.ArrayList<Tan>();
显示界面的方法:在窗体上添加了2个面板,进度条、按钮都在面板1上,弹球在面板2 上运动。点击按钮会有不同的值,这个值会被控制进度条、控制弹球、和弹球的监听器类使用,以控制弹球运动和进度条。
public void showt(){ this.setTitle("弹球"); this.setSize(550,600); JPanel p1=new JPanel(), p2=new JPanel();//创建2个面板 //给面板设置位置 this.add(p1,BorderLayout.NORTH); this.add(p2,BorderLayout.SOUTH); p1.setBounds(0,0,550, 20); p2.setBounds(0,20,550, 500); JProgressBar p=new JProgressBar();//创建一个进度条对象 p.setMaximum(2000);//设置进度条的最大值是300 a=new JButton("开始"); b=new JButton("暂停"); //将进度条、按钮添加到面板1上 p1.add(p); p1.add(a); p1.add(b); p1.setBackground(Color.blue);//面板1的背景为蓝色 this.setResizable(true);//是否能最大化 this.setDefaultCloseOperation(3);//关闭窗体是退出程序 this.setLocationRelativeTo(null);//窗体居中显示 this.setVisible(true);//窗体可见 this.validate(); //得到画布对象 Graphics g = this.getGraphics(); int a1=0,b1=1,c=2,d=3; //创建线程 Tan t1=new Tan(a1,g); arr.add(t1);//将线程1加入队列中 //启动线程 t1.start(); System.out.println("第一个线程已启动"); Tan t2=new Tan(b1,g); arr.add(t2);//将线程2加入队列中 //启动线程 t2.start();//start()调用run()方法 System.out.println("第二个线程已启动"); Tan t3=new Tan(c,g); arr.add(t3);//将线程3加入队列中 t3.start();//启动线程 System.out.println("第三个线程已启动"); Tan t4=new Tan(d,g); arr.add(t4);//将线程4加入队列中 t4.start();//启动线程 System.out.println("第四个线程已启动"); Progressj tt=new Progressj(p);//创建控制进度条的线程 tt.start();//启动线程 Jian ji=new Jian(arr);//创建一个弹球的监视器线程对象 ji.start();//启动线程 System.out.println("监视线程已启动"); ActionListener ac=new ActionListener(){ public void actionPerformed(ActionEvent e){ if(e.getSource()==a){m=1;}//点击“开始”按钮,m的值为1 else if(e.getSource()==b){ m=0;}//点击“暂停”按钮,m的值为0 } }; //给按钮添加监视器 a.addActionListener(ac); b.addActionListener(ac); }
进度条的类:这个类用来控制进度条
public class Progressj extends Thread{ JProgressBar p; static int x=0; public Progressj(JProgressBar p){ this.p=p; } public void run(){ jin(); } public void jin(){ while(true){ p.setValue(x);//设置进度条的当前值 if(Mainr.m==1&&x<2000) {x+=5; } try{ Thread.sleep(200); }catch(Exception e){ } } } }
弹球运动的类:当弹球碰到壁后就改变运动方向,当不同方向的球碰撞后,就反方向运动。
注意:在每一个方向的弹球运动方法中,当弹球碰撞后(即t1为非零的值),要先改变t1的值,再调用弹球另一个方向运动的方法。因为每一个弹球的运动都是一个线程,在时间没有结束时吗,会不停的执行下去,若在调用弹球方向运动方法后改变t1的值为0,那么,弹球碰撞后会分开,但碰到壁后就停止消失,再两个弹球出现在碰撞的地方,分开,再运动。
public class Tan extends Thread { int a;//a代表哪一个弹球线程 Graphics g; int m,n,k;//k记录弹球的运动方法 int t1=0,t2,t3; Color co;//弹球的颜色 public Tan(int a,Graphics g){ this.a=a; this.g=g; } public void run(){ if(a==0) { rightstoleft(505,60,Color.green); }//右上角到左下角的初始球 if(a==1) { leftstoright(5,60,Color.red);}//从左上角到右下角 if(a==2) { rightsytoleft(505,555,Color.yellow);}//从右下角到左上角 if(a==3) { leftsytoright(5,555,Color.pink);}//从左下角到右上角 } //从右上角到左下角(x,y)为弹球的坐标,b代表哪个弹球 public void rightstoleft(int x,int y,Color c){ boolean a=true; while(a){ g.clearRect(x+2, y-1, 40, 40); g.setColor(c); g.fillOval(x, y, 40, 40); if(Mainr.m==1&&Progressj.x<2000) {x-=2;y++;} if(x<=6&&x>=5&&y<555) {leftstoright(x,y,c); a=!a; }//然后左上右下,a的值变化,该方法执行结束,进行下一个方法 if(y==555&&x>5) {rightsytoleft(x, y,c);a=!a; } //从右下角到左上角 if(x==5&&y==555) {leftsytoright(x,y,c);a=!a; }//从左下角到右上角 //当弹球在此方向运动的时候发生碰撞:t1=1,则返回,即从左下方向右上方运动。 if(t1==1) {t1=0;leftsytoright(t2,t3,c);a=!a;}//要先将t1=0,再才能够调用弹球运动的方法 //暂停一下 try{ Thread.sleep(15); } catch(Exception e){ } m=x;n=y; k=1;co=c; } } //从左上角到右下角 public void leftstoright(int x,int y,Color c){ boolean a=true; while(a){ g.clearRect(x-2, y-1, 40,40); g.setColor(c); g.fillOval(x, y, 40, 40); if(Mainr.m==1&&Progressj.x<2000) { x+=2;y++;} if(x>=504&&x<=505&&y<555) {rightstoleft(x,y,c); a=!a; }//然后右上左下 if(y==555&&x<505) {leftsytoright(x,y,c); a=!a; }//然后左下右上 if(x==505&&y==555) {rightsytoleft(x, y,c); a=!a; }//从右下角到左上角 //当弹球在此方向运动的时候发生碰撞:t1=2,则返回,即从右下方向左上方运动。 if(t1==2) {t1=0;rightsytoleft(t2,t3,c);a=!a; } //暂停一下 try{ Thread.sleep(5); } catch(Exception e){ } m=x;n=y; k=2;co=c; } } //从右下角到左上角 public void rightsytoleft(int x, int y,Color c){ boolean a=true; while(a){ g.clearRect(x+1, y+2, 40, 40); g.setColor(c); g.fillOval(x, y, 40, 40); if(Mainr.m==1&&Progressj.x<2000) {x--;y-=2;} if(x==5&&y>60) {leftsytoright(x,y,c); a=!a; }//从左下角到右上角 if(x==5&&y==60) {leftstoright(x,y,c); a=!a; }//从左上角到右下角 if(y>=60&&y<=61&&x>5) {rightstoleft(x,y,c); a=!a; }//然后右上左下 //当弹球在此方向运动的时候发生碰撞:t1=3,则返回,即从左上方向右下方运动。 if(t1==3) {t1=0;leftstoright(t2,t3,c);a=!a; } //暂停一下 try{ Thread.sleep(10); } catch(Exception e){ } m=x;n=y;k=3;co=c; } } //从左下角到右上角 public void leftsytoright(int x,int y,Color c){ boolean a=true; while(a){ g.clearRect(x-2, y+1, 40, 40); g.setColor(c); g.fillOval(x, y, 40, 40); if(Mainr.m==1&&Progressj.x<2000) {x+=2;y--;} if(x>=504&&x<=505&&y>60) {rightsytoleft(x,y,c); a=!a; }//然后右下左上 if(x==505&&y==60) {rightstoleft( x,y,c); a=!a; }//然后右上左下 if(y==60&&x<505) {leftstoright(x,y,c); a=!a; }//从左上角到右下角 //当弹球在此方向运动的时候发生碰撞:t1=4,则返回,即从右上到左下运动。 if(t1==4) {t1=0;rightstoleft(t2,t3,c);a=!a; } //暂停一下 try{ Thread.sleep(20); } catch(Exception e){ } m=x;n=y;k=4;co=c; } } //碰撞的情况方法 public void pu(int t1,int t2,int t3,Color c){ //t1为传过来的k,t2,t3为弹球的位置 this.t1=t1; this.t2=t2; this.t3=t3; } }
弹球的监听器线程:获得队列中的数据,比较两个弹球的坐标,看是否在碰撞区内,在碰撞区内,调用tan 线程内处理碰撞情况的方法。
public class Jian extends Thread{ java.util.ArrayList<Tan> arr; //传递队列 public Jian(java.util.ArrayList<Tan> arr){ this.arr=arr; } public void run(){ bijiao(); } public void bijiao(){ while(true){ for(int i=0;i<arr.size()-1;i++){ for(int j=i+1;j<arr.size();j++){ Tan t1=arr.get(i),t2=arr.get(j);
//获得弹球的运动方向值,坐标,颜色
int x1=t1.m,
y1=t1.n,
x2=t2.m,
y2=t2.n,
k1=t1.k,
k2=t2.k;
Color c1=t1.co,
c2=t2.co;
if(Mainr.m==1&&Progressj.x<2000){//在没有暂停并且时间还没有结束情况下
if(k1!=k2&&Math.abs(x1-x2)<=40&&Math.abs(y1-y2)<=40){//在碰撞区内
t1.pu(k1,x1,y1,c1);//调用tan类中的方法,用来实现碰撞
t2.pu(k2,x2,y2,c2);
}
}
}
}
try{
Thread.sleep(200);
}catch(Exception e){
e.printStackTrace();
}
}
}
}
下面这张图片是界面刚刚出来是弹球还没有运动是的图片
下面这张图片是弹球运动过程中,被暂停后图片。你可以看到图中的粉红色弹球和红色的弹球离得很近。她们是碰撞后刚刚分开的图片。
下面的这张图片是在弹球运动时,打印出的弹球运动位置。上面有一行显示了“1<<<<3>>>311与293相等”,是红球和粉红弹球碰撞是的结果311和293是代表两球的x 坐标,1和3 代表他们在队列中的位置。下面也显示了碰撞后他们各自的运动方向