Java线程进阶:无人机自动防空平台开发教程

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);}}}

以上就是我本次分享,感谢观看!

Read more

【C++:哈希表】从哈希冲突到负载因子:熟悉哈希表的核心机制

【C++:哈希表】从哈希冲突到负载因子:熟悉哈希表的核心机制

🔥艾莉丝努力练剑:个人主页 ❄专栏传送门:《C语言》、《数据结构与算法》、C/C++干货分享&学习过程记录、Linux操作系统编程详解、笔试/面试常见算法:从基础到进阶、测试开发要点全知道 ⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平 🎬艾莉丝的简介: 🎬艾莉丝的C++专栏简介: 目录 C++的两个参考文档 前情提示 1  ~>  初始哈希 2  ~>  直接定址法 2.1  概念 2.2  示例:字符串中的第一个唯一字符 3  ~>  哈希的一些概念 3.1  哈希冲突 3.2  负载因子 3.3

By Ne0inhk
临床智能体AI与环境感知AI的融合:基于python的医疗自然语言处理深度分析

临床智能体AI与环境感知AI的融合:基于python的医疗自然语言处理深度分析

引言 医疗领域的数智化进程正以前所未有的速度推进,人工智能技术的应用尤为显著。随着大型语言模型(LLMs)的迅猛发展,医疗AI已从简单的辅助工具升级为复杂的智能体系统。临床智能体AI与环境感知AI的融合代表了医疗AI的最新发展方向,为重塑医疗运营自然语言处理提供了全新视角。 本研究聚焦于临床智能体AI与环境感知AI的融合技术,深入探讨其在医疗运营自然语言处理中的应用。我们将详细分析spaCy、BERT-Med、Whisper、Kaldi、Drools、AWS Lex、PySyft和Intel SGX等先进工具在这一领域的应用,并提供完整的Python代码实现。 临床智能体AI与环境感知AI的基本概念 临床智能体AI的定义与特征 临床智能体AI(Clinical AI Agents)是指在临床环境中运行,能够感知医疗场景、理解患者需求、做出诊断决策并执行医疗相关任务的人工智能系统。这类智能体具备以下核心特征: 1. 感知能力:能够通过多种传感器和数据源获取医疗相关信息 2. 理解能力:能够理解复杂的医学知识和患者需求 3. 决策能力:能够基于医学知识和患者数据做出合理

By Ne0inhk

《C++ Primer》第5版 友元 (friend)

C++ 教材(《C++ Primer》第5版)章节标题为: 7.2.1 友元 (friend) 本节核心内容是:当类的数据成员设为 private 时,如何让非成员函数(如 read, print, add)能够访问这些私有成员?答案是——使用 friend 关键字声明“友元函数”。 这是面向对象设计中“封装性”与“接口灵活性”之间的重要平衡机制。 🔍 逐段解析 ✅ 第一段:问题背景 既然 Sales_data 的数据成员是 private 的,我们的 read、print 和 add 函数也就无法正常编译了,这是因为尽管这几个函数是类的接口的一部分,但它们不是类的成员。 💡 核心要点: * 如果将

By Ne0inhk

Visual C++运行库终极修复方案:一键解决所有程序启动问题

还在为各种"无法启动此程序"的错误提示而烦恼吗?每次安装新软件都像在拆盲盒,不知道会遇到什么奇怪的启动问题?别担心,这正是Visual C++运行库缺失的典型症状!本文将为你提供一套完整的终极修复方案,让你彻底告别这些烦恼。 【免费下载链接】vcredistAIO Repack for latest Microsoft Visual C++ Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你的问题,我们懂! 想象一下这些场景: * 下载了心仪已久的游戏,双击后却毫无反应 * 安装了专业软件,却提示"缺少xxx.dll文件" * 系统更新后,原本正常的程序突然无法运行 这些问题的根源往往很简单:缺少了正确的Visual C++运行库。就像邀请外国专家来工作,却没有配备翻译一样,

By Ne0inhk