Java线程进阶:无人机自动防空平台开发教程
大家好!今天我们利用上次提到的线程来开发一个无人机自动防空平台,主要功能是无人机巡逻发现并攻击敌机,在过程中可随时添加无人机和敌机,程序中还设有机库,无人机没电或弹药不足即刻前往机库进行恢复。

第一版本的效果是这样,无人机只在红色矩形内生产和移动,红色矩形表示无人机要巡逻的地方,敌机会从红色矩形外进入。
今天我带大家完成第一部分,无人机和敌机的生成、绘制和移动。
一、绘制窗体
首先我们要把窗体绘制出来,基本的窗体绘制之前的文章有提到,大家自行查看。我们是通过点击按钮来生产无人机和敌机,所以要在窗体下面设置按钮,因为窗体没有用流式布局,若添加按钮,则按钮会占满整个窗体。若只添加一个按钮,则使用边框布局,将按钮放在窗体下面,但若要添加多个按钮还需要添加面板对象JPanel,将按钮添加到面板上,再将面板使用边框布局添加到窗体上。
setTitle("智能无人机指挥系统");setSize(1200,1000);setDefaultCloseOperation(3);setLocationRelativeTo(null);//居中显示//添加面板JPanel btnPanel =newJPanel(); btnPanel.setBackground(Color.LIGHT_GRAY);//设置颜色//添加按钮JButton btn =newJButton("生产无人机"); btnPanel.add(btn);JButton btn1 =newJButton("生产入侵者"); btnPanel.add(btn1);add(btnPanel,BorderLayout.SOUTH);//在窗体上添加面板//因为没有给窗体设置流式布局,所以按钮会占满整个窗体,使用边框布局Borderlayout将按钮放在窗体下面//add(btn,BorderLayout.SOUTH);//因为要添加多个按钮所以此方法不用setVisible(true);二、无人机的生成
因为要生成多个无人机,所以可以将无人机设置成一个类,在类中添加无人机的属性和方法。

我们将无人机制作成如图所示的样子。浅绿色表示无人机的雷达范围,在雷达范围中扫描敌机,蓝色表示无人机本机,红色表示无人机的状态,比如电量充足状态,电量不足状态等。
1.无人机的属性
坐标、速度、雷达范围、无人机尺寸、无人机状态等
//属性int x,y;//坐标int speedx,speedy;//速度int size;//无人机尺寸int state;//无人机状态int stateSize;//无人机状态圆的大小int scanSize;//雷达范围2.无人机的方法
- 构造方法
在构造方法中设置好无人机的属性
//构造方法publicDrone(int x,int y,int speedx,int speedy,int state){this.x = x;this.y = y;this.speedx = speedx;this.speedy = speedy;this.state = state;this.scanSize =100;this.size =30;this.stateSize =15;}- 绘制方法
通过画不同的圆绘制无人机,注意圆的大小、位置、颜色要合适。
//绘制无人机方法publicvoiddrawDrone(Graphics bg){Color color1 =newColor(0,255,150,90); bg.setColor(color1); bg.fillOval(x,y,scanSize,scanSize);Color color2 =newColor(62,62,222); bg.setColor((color2)); bg.fillOval(x+35,y+35,size,size);Color color3 =newColor(255,0,0); bg.setColor(color3); bg.fillOval(x+42,y+42,stateSize,stateSize);}- 移动方法
当无人机碰到红色矩形则反弹,速度变为相反数。
//无人机移动方法publicvoidmove(){if(x>1000-scanSize||x<200){//碰到边界 speedx =-speedx;//改变无人机x运动方向}if(y>780-scanSize||y<180){//碰到边界 speedy =-speedy;//改变无人机y运动方向} x+=speedx; y+=speedy;}三、敌机的生成
和无人机一样,敌机也封装成一个类,包含属性和方法。
publicclassInvader{//属性int x,y;//坐标int speedx,speedy;//速度int size;//尺寸int blood;//方法//构造方法publicInvader(int x,int y,int speedx,int speedy,int size){this.x = x;this.y = y;this.speedx = speedx;this.speedy = speedy;this.size = size;this.blood =100;}//绘制方法publicvoiddrawInvader(Graphics g){if(blood<=0){return;} g.setColor(Color.BLACK); g.fillOval(x,y,size,size); g.setColor(Color.RED); g.drawOval(x-1,y-1,size+2,size+2);}//移动方法publicvoidmove(){if(blood<=0){return;}if(x-1>1200-(size+2)||x-1<0){//碰到边界 speedx =-speedx;//改变x运动方向}if(y-1>960-(size+2)||y-1<20){//碰到边界 speedy =-speedy;//改变y运动方向} x+=speedx; y+=speedy;}}敌机在红色矩形外产生,所以碰到边界的范围有所变化。
四、无人机线程
当无人机和敌机移动时,并不会跟我们想象的一样移动,移动路程上的图并不会消失,一直留在窗体上,只有当无人机和敌机不再移动窗体才可刷新。
但我们的无人机和敌机需要一直移动,要解决这个问题,我们上篇文章提到的线程就派上用场啦!
这里我们需要创建一个无人机线程,将每一次的移动画到一张缓冲图片上,将图片直接显示到窗体上,在每一次移动之间画一张白饭覆盖之前的图片,就能解决这个问题了。
publicclassDroneThreadextendsThread{ArrayList<Drone> droneList;ArrayList<Invader> invaderList;Graphics g;publicDroneThread(Graphics g){this.g=g;}//重写run方法publicvoidrun(){while(true){try{Thread.sleep(30);//延时处理}catch(InterruptedException e){thrownewRuntimeException(e);}//缓冲图片:将画的过程显示在图片上,画完再将整张图片显示在窗体上//高度960是给按钮留一定位置使按钮不会被刷新BufferedImage img =newBufferedImage(1200,960,2);Graphics bg = img.getGraphics();//画白板 bg.setColor(Color.WHITE); bg.fillRect(0,0,1200,960); bg.setColor(Color.RED); bg.drawRect(200,180,800,600);//800*600 无人机防守范围//遍历无人机数组,取出无人机对象,调用绘制和移动方法for(int i=0;i<droneList.size();i++){Drone drone = droneList.get(i); drone.drawDrone(bg); drone.move();}for(int i =0; i < invaderList.size(); i++){Invader invader = invaderList.get(i); invader.drawInvader(bg); invader.move();} g.drawImage(img,0,0,null);}}}五、监听器的添加及多线程间的联系
当我们按下不同按钮,对应的物体就会生产出来,所以我们需要给按钮添加动作监听器。
但是怎么做到按一下生产无人机按钮就能生产一个无人机呢?
相信大家看到前面的代码也会有这个疑问?也会想不明白为什么会有ArrayList数组的出现。

上图就是多线程之间建立联系的方法,创建一个无人机数组,将无人机数组放到内存空间中,并传入监听器和无人机线程中,每点击一次按钮无人机数组就添加一个无人机对象,在无人机线程中遍历该数组画出所有无人机,敌机也是一样的方法。
程序完整代码
DroneUI:
importjavax.swing.*;importjava.awt.*;importjava.util.ArrayList;publicclassDroneUIextendsJFrame{//无人机数组ArrayList<Drone> droneList =newArrayList<>();//入侵者数组ArrayList<Invader> invaderList =newArrayList<>();Graphics g;publicDroneUI(){setTitle("智能无人机指挥系统");setSize(1200,1000);setDefaultCloseOperation(3);setLocationRelativeTo(null);//居中显示//添加面板JPanel btnPanel =newJPanel(); btnPanel.setBackground(Color.LIGHT_GRAY);//设置颜色//添加按钮JButton btn =newJButton("生产无人机"); btnPanel.add(btn);JButton btn1 =newJButton("生产入侵者"); btnPanel.add(btn1);add(btnPanel,BorderLayout.SOUTH);//在窗体上添加面板//因为没有给窗体设置流式布局,所以按钮会占满整个窗体,使用边框布局Borderlayout将按钮放在窗体下面//add(btn,BorderLayout.SOUTH);//因为要添加多个按钮所以此方法不用setVisible(true);//动作监听器DroneListener dl =newDroneListener(); btn.addActionListener(dl);//给按钮添加动作监听器 btn1.addActionListener(dl);//给按钮添加动作监听器 g =getGraphics();//从窗体上获取画笔DroneThread dt =newDroneThread(g);//无人机线程//将共享内存空间中的数组传到两个线程中 dl.droneList = droneList;//监听器线程 dt.droneList = droneList;//无人机线程 dl.invaderList = invaderList; dt.invaderList = invaderList;//启动无人机线程 dt.start();//在无人机所有动作完成后启动无人机线程,使无人机线程启动更加安全}//启动线程不要写到下面这种重复调用的方法里面//paint方法:绘制窗体 刷新窗体publicvoidpaint(Graphics g){//Graphics 图形工具类 提供坐标,就可以绘制图形super.paint(g);}publicstaticvoidmain(String[] args){DroneUI ui =newDroneUI();}}Drone:
importjava.awt.*;publicclassDrone{//属性int x,y;//坐标int speedx,speedy;//速度int size;//无人机尺寸int state;//无人机状态int stateSize;//无人机状态圆的大小int scanSize;//雷达范围//方法//构造方法publicDrone(int x,int y,int speedx,int speedy,int state){this.x = x;this.y = y;this.speedx = speedx;this.speedy = speedy;this.state = state;this.scanSize =100;this.size =30;this.stateSize =15;}//绘制无人机方法publicvoiddrawDrone(Graphics bg){Color color1 =newColor(0,255,150,90); bg.setColor(color1); bg.fillOval(x,y,scanSize,scanSize);Color color2 =newColor(62,62,222); bg.setColor((color2)); bg.fillOval(x+35,y+35,size,size);Color color3 =newColor(255,0,0); bg.setColor(color3); bg.fillOval(x+42,y+42,stateSize,stateSize);}//无人机移动方法publicvoidmove(){if(x>1000-scanSize||x<200){//碰到边界 speedx =-speedx;//改变无人机x运动方向}if(y>780-scanSize||y<180){//碰到边界 speedy =-speedy;//改变无人机y运动方向} x+=speedx; y+=speedy;}}Invader:
importjava.awt.*;publicclassInvader{//属性int x,y;//坐标int speedx,speedy;//速度int size;//尺寸int blood;//方法//构造方法publicInvader(int x,int y,int speedx,int speedy,int size){this.x = x;this.y = y;this.speedx = speedx;this.speedy = speedy;this.size = size;this.blood =100;}//绘制方法publicvoiddrawInvader(Graphics g){if(blood<=0){return;} g.setColor(Color.BLACK); g.fillOval(x,y,size,size); g.setColor(Color.RED); g.drawOval(x-1,y-1,size+2,size+2);}//移动方法publicvoidmove(){if(blood<=0){return;}if(x-1>1200-(size+2)||x-1<0){//碰到边界 speedx =-speedx;//改变x运动方向}if(y-1>960-(size+2)||y-1<20){//碰到边界 speedy =-speedy;//改变y运动方向} x+=speedx; y+=speedy;}}DroneThread:
importjava.awt.*;importjava.awt.image.BufferedImage;importjava.util.ArrayList;publicclassDroneThreadextendsThread{ArrayList<Drone> droneList;ArrayList<Invader> invaderList;Graphics g;publicDroneThread(Graphics g){this.g=g;}//重写run方法publicvoidrun(){while(true){try{Thread.sleep(30);//延时处理}catch(InterruptedException e){thrownewRuntimeException(e);}//缓冲图片:将画的过程显示在图片上,画完再将整张图片显示在窗体上//高度960是给按钮留一定位置使按钮不会被刷新BufferedImage img =newBufferedImage(1200,960,2);Graphics bg = img.getGraphics();//画白板 bg.setColor(Color.WHITE); bg.fillRect(0,0,1200,960); bg.setColor(Color.RED); bg.drawRect(200,180,800,600);//800*600 无人机防守范围//遍历无人机数组,取出无人机对象,调用绘制和移动方法for(int i=0;i<droneList.size();i++){Drone drone = droneList.get(i); drone.drawDrone(bg); drone.move();}for(int i =0; i < invaderList.size(); i++){Invader invader = invaderList.get(i); invader.drawInvader(bg); invader.move();} g.drawImage(img,0,0,null);}}}DroneListener:
importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.util.ArrayList;importjava.util.Random;publicclassDroneListenerimplementsActionListener{ArrayList<Drone> droneList;ArrayList<Invader> invaderList;//随机数Random ran =newRandom();publicvoidactionPerformed(ActionEvent e){String name = e.getActionCommand();if(name.equals("生产无人机")){int x = ran.nextInt(200,700);int y = ran.nextInt(180,680);int speedx = ran.nextInt(5)-2;//-2~2 5的意思是随机0 1 2 3 4 不包括5int speedy = ran.nextInt(5)-2;//-2~2while(true){if(speedx!=0&&speedy!=0){break;} speedx = ran.nextInt(5)-2;//-2~2 5的意思是随机0 1 2 3 4 不包括5 speedy = ran.nextInt(5)-2;//-2~2}//点击按钮 生产无人机Drone drone =newDrone(x, y, speedx, speedy,0); droneList.add(drone);}elseif(name.equals("生产入侵者")){//入侵者在红框四周产生//防止入侵者在反弹边界生成将x,y值减小一点int x = ran.nextInt(1150);int y = ran.nextInt(21,910);while(true){if(x<200||x>1000||y<180||y>780){break;} x = ran.nextInt(1140); y = ran.nextInt(21,910);}int speedx = ran.nextInt(5)-2;//-2~2 5的意思是随机0 1 2 3 4 不包括5int speedy = ran.nextInt(5)-2;//-2~2while(true){if(speedx!=0&&speedy!=0){break;} speedx = ran.nextInt(5)-2;//-2~2 5的意思是随机0 1 2 3 4 不包括5 speedy = ran.nextInt(5)-2;//-2~2}//点击按钮 生产入侵者Invader invader =newInvader(x,y,speedx,speedy,45); invaderList.add(invader);}}}以上就是我本次分享,感谢观看!