《智能仿真无人机平台(多线程V2.0)技术笔记》(线程进阶: 无人机自动防空平台开发教程)

智能仿真无人机平台(多线程V2.0)技术笔记

本文记录一个包含无人机生产、入侵者生成、运动控制、雷达扫描功能的多线程GUI项目,涉及5个核心类的设计与实现,重点说明关键技术点、注意事项及代码注释。

一、核心类:Drone(无人机类)

负责定义无人机的属性、绘制逻辑和运动规则,是业务核心实体。
java 复制代码
package duoxiancheng.xq0122.dronev2;
import java.awt.*;

/**
 * @author xuqiang
 * @date 2026/1/22  16:07
 * @description 无人机实体类:封装属性、绘制逻辑、运动规则
 */
public class Drone {
    int x,y; // 无人机坐标(雷达扫描区域左上角起点)
    int speedx,speedy; // 水平/垂直移动速度
    int size; // 无人机机身大小
    int state; // 无人机状态(预留扩展:如巡逻/战斗/返航)
    int stateSize; // 状态指示灯大小
    int scanSize; // 雷达扫描范围大小

    // 构造方法:初始化无人机核心属性
    public Drone(int x,int y,int state,int speedx,int speedy){
        this.x=x;
        this.y=y;
        this.state=state;
        this.speedx=speedx;
        this.speedy=speedy;
        this.size=30; // 机身默认30px
        this.stateSize=15; // 状态灯默认15px
        this.scanSize=100; // 雷达扫描范围默认100px(半透明蓝色)
    }

    // 绘制无人机:分层绘制(雷达区域→机身→状态灯)
    public void drawDrone(Graphics bg) {
        // 1. 绘制雷达扫描区域(半透明蓝色,alpha=60实现透明效果)
        Color radarColor = new Color(0, 0, 255, 60);
        bg.setColor(radarColor);
        bg.fillOval(x, y, scanSize, scanSize); // 雷达区域为椭圆形
        
        // 2. 绘制无人机机身(绿色实体圆)
        Color bodyColor = new Color(64, 195, 66);
        bg.setColor(bodyColor);
        bg.fillOval(x + 35, y + 35, size, size); // 机身位置相对于雷达区域偏移
        
        // 3. 绘制状态指示灯(红色实体圆,默认异常状态,可扩展状态切换)
        Color stateColor = new Color(255, 0, 0);
        bg.setColor(stateColor);
        bg.fillOval(x + 42, y + 42, stateSize, stateSize);
    }

    // 无人机运动逻辑:边界反弹+位置更新
    public void move(){
        // 水平边界检测:左边界200px,右边界1000px(雷达区域不超出红色矩形战斗区)
        if(x < 200 || (x+scanSize) > 1000){
            speedx = -speedx; // 碰到边界反向运动
        }

        // 垂直边界检测:上边界175px,下边界775px(与战斗区边界对齐)
        if (y < 175 || (y+scanSize) > 775){
            speedy = -speedy; // 碰到边界反向运动
        }

        x+=speedx; // 更新水平位置
        y+=speedy; // 更新垂直位置
    }
}

关键注意点

  1. 坐标关系:无人机的x,y是雷达区域的左上角,机身和状态灯基于此坐标偏移,需保持绘制层级顺序(雷达→机身→状态灯);
  2. 边界控制:运动边界与UI中的红色战斗区(200,175,800,600)严格对齐,避免无人机超出战斗范围;
  3. 透明效果:通过Color构造方法的第四个参数(alpha值)实现雷达半透明,需注意alpha范围为0-255;
  4. 预留扩展:state属性未实际使用,可扩展为状态枚举(如巡逻/战斗/返航),配合stateColor动态切换指示灯颜色。

二、核心类:Intruder(入侵者实体类)

定义入侵者的属性、绘制逻辑和运动规则,与无人机形成对抗关系。
java 复制代码
package duoxiancheng.xq0122.dronev2;
import java.awt.*;

/**
 * @author xuqiang
 * @date 2026/1/22  16:31
 * @description 入侵者实体类:封装属性、绘制逻辑、运动规则、血量机制
 */
public class Intruder {
    int x,y; // 入侵者坐标(左上角)
    int speedx,speedy; // 水平/垂直移动速度
    int size; // 入侵者大小
    int blood; // 入侵者血量(用于后续攻击逻辑扩展)

    // 构造方法:初始化入侵者核心属性
    public Intruder(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; // 默认血量100
    }

    // 绘制入侵者:血量>0时才绘制(死亡后隐藏)
    public void drawIntruder(Graphics g){
        if(blood <= 0){
            return; // 血量为0,不绘制(视为被消灭)
        }
        g.setColor(Color.BLACK);
        g.fillOval(x,y,size,size); // 黑色实体圆作为入侵者主体
        g.setColor(Color.RED);
        g.drawOval(x-1,y-1,size+2,size+2); // 红色边框增强视觉区分
    }

    // 入侵者运动逻辑:边界反弹+位置更新(与无人机边界不同)
    public void move(){
        if(blood <= 0){
            return; // 血量为0,停止运动
        }

        // 水平边界:整个窗口(0-1200px),与UI窗口宽度一致
        if(x < 0 || (x+size) > 1200){
            speedx = -speedx; // 边界反弹
        }
        // 垂直边界:整个窗口(0-950px),与绘制缓冲区高度一致
        if(y < 0 || (y+size) > 950){
            speedy = -speedy; // 边界反弹
        }

        x += speedx; // 更新水平位置
        y += speedy; // 更新垂直位置
    }
}

关键注意点

  1. 边界差异:入侵者运动边界是整个窗口(1200x950),而无人机仅在战斗区(200-1000x175-775)内运动,体现"外部入侵"的业务逻辑;
  2. 血量机制:blood属性预留攻击逻辑扩展,当前仅用于控制绘制和运动状态,后续可添加无人机攻击减血功能;
  3. 视觉设计:黑色主体+红色边框,与无人机的绿色机身形成鲜明对比,便于视觉区分。

三、事件监听器:DroneListener(按钮事件处理)

处理"生产无人机"和"生产入侵者"按钮的点击事件,负责实体对象的创建和集合添加。
java 复制代码
package duoxiancheng.xq0122.dronev2;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;

/**
 * @author xuqiang
 * @date 2026/1/22  16:32
 * @description 按钮事件监听器:处理无人机和入侵者的创建逻辑
 */
public class DroneListener implements ActionListener {
    ArrayList<Drone> droneList; // 存储所有无人机的集合(由UI类注入初始化)
    ArrayList<Intruder> intruderList; // 存储所有入侵者的集合(由UI类注入初始化)
    Random random = new Random(); // 随机数生成器(用于位置和速度随机)

    @Override
    public void actionPerformed(ActionEvent e) {
        String ac = e.getActionCommand(); // 获取按钮点击命令(与按钮文本一致)

        // 处理"生产无人机"按钮点击
        if(ac.equals("生产无人机")){
            // 随机位置:x在200-900px(战斗区内),y在175-675px(战斗区内)
            int x = 200 + random.nextInt(700); // 700=1000-200,确保x+scanSize≤1000
            int y = 175 + random.nextInt(500); // 500=775-175,确保y+scanSize≤775
            // 随机速度:-2~2(包含0,可后续优化避免静止)
            int speedx = random.nextInt(5) - 2;
            int speedy = random.nextInt(5) - 2;
            // 创建无人机对象(state=0预留状态)
            Drone drone = new Drone(x,y,0,speedx,speedy);
            // 添加到集合(集合由UI初始化,避免空指针)
            droneList.add(drone);
        }
        // 处理"生产入侵者"按钮点击
        else if(ac.equals("生产入侵者")){
            int intruderSize = 45; // 入侵者固定大小45px
            // 初始随机位置:x在200-1355px,y在175-1080px(覆盖窗口+外部区域)
            int x = 200 + random.nextInt(1155);
            int y = 175 + random.nextInt(905);

            // 循环确保入侵者初始位置在战斗区外部(业务规则:从外部入侵)
            while (true){
                // 条件:入侵者完全在战斗区(200-1000x175-775)外部
                if(x + intruderSize <= 200 || x >= 1000 || y + intruderSize <= 175 || y + intruderSize >= 775){
                    break; // 位置合法,退出循环
                }
                // 位置非法,重新随机
                x = random.nextInt(1150);
                y = random.nextInt(900);
            }

            // 随机速度:-2~2(包含0,可后续优化避免静止)
            int speedx = random.nextInt(5) - 2;
            int speedy = random.nextInt(5) - 2;
            // 创建入侵者对象
            Intruder itd = new Intruder(x,y,speedx,speedy,intruderSize);
            // 添加到集合(集合由UI初始化)
            intruderList.add(itd);
        }
    }
}

关键注意点

  1. 集合注入:droneListintruderList由UI类初始化并注入,避免直接创建导致的多实例问题,同时防止空指针;
  2. 位置合法性:入侵者通过while循环强制初始位置在战斗区外部,符合"入侵"的业务逻辑,需注意边界条件的准确性(包含入侵者大小);
  3. 随机范围:无人机位置严格限制在战斗区内,确保初始位置合法,避免一创建就触发边界反弹;
  4. 速度优化:当前速度可能为0(导致物体静止),可后续修改为random.nextInt(4) - 2(排除0)或添加非零校验。

四、多线程类:DroneThread(绘制与运动控制线程)

负责后台循环执行绘制、运动更新、雷达扫描逻辑,避免UI线程阻塞。
java 复制代码
package duoxiancheng.xq0122.dronev2;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

/**
 * @author xuqiang
 * @date 2026/1/22  18:53
 * @description 后台线程:负责绘制刷新、实体运动更新、雷达扫描检测
 */
public class DroneThread extends Thread{
    ArrayList<Drone> droneList; // 无人机集合(与UI、监听器共享)
    ArrayList<Intruder> intruderList; // 入侵者集合(与UI、监听器共享)
    Graphics g; // 窗口绘图上下文(从UI获取)

    // 构造方法:接收UI的绘图上下文
    public DroneThread(Graphics g){
        this.g=g;
    }

    // 线程核心逻辑:循环执行(绘制→运动→扫描)
    @Override
    public void run(){
        while (true) { // 无限循环,保持后台运行
            // 1. 创建双缓冲图像(解决绘制闪烁问题)
            BufferedImage img = new BufferedImage(1200,950,BufferedImage.TYPE_INT_RGB);
            Graphics bg = img.getGraphics(); // 获取缓冲图像的绘图上下文

            // 2. 绘制背景和战斗区
            bg.setColor(Color.WHITE);
            bg.fillRect(0,0,1200,950); // 白色背景(覆盖整个窗口)
            bg.setColor(Color.RED);
            bg.drawRect(200,175,800,600); // 红色战斗区边框(核心交互区域)

            // 3. 无人机更新:运动+绘制(集合非空校验,避免空指针)
            if (droneList != null && !droneList.isEmpty()) {
                for (Drone drone : droneList) {
                    drone.move(); // 先更新位置,再绘制(避免绘制延迟)
                    drone.drawDrone(bg);
                }
            }

            // 4. 入侵者更新:绘制+运动(顺序不影响,与无人机逻辑一致即可)
            if (intruderList != null && !intruderList.isEmpty()) {
                for (Intruder intruder : intruderList) {
                    intruder.drawIntruder(bg);
                    intruder.move();
                }
            }

            // 5. 雷达扫描检测:仅取第一个无人机的扫描区域(可扩展为所有无人机)
            if(droneList != null && droneList.size()>0){
                Drone drone = droneList.get(0);
                // 遍历雷达扫描区域的每个像素(x到x+scanSize,y到y+scanSize)
                for (int i = drone.x; i < drone.x + drone.scanSize ; i++) {
                    for(int j = drone.y;j < drone.y + drone.scanSize;j++) {
                        // 边界校验:避免像素坐标超出缓冲图像范围(空指针)
                        if(i <0 || i>=1200 || j<0 || j>=950){
                            continue;
                        }
                        // 获取像素RGB值,转换为Color对象
                        int colorNum = img.getRGB(i,j);
                        Color c = new Color(colorNum);
                        // 灰度值判断:(R+G+B)/3 <10 视为黑色(入侵者主体颜色)
                        if((c.getRed() + c.getBlue() + c.getGreen())/3 < 10){
                            System.out.println("雷达扫描到了~");
                        }
                    }
                }
            }

            // 6. 将缓冲图像绘制到窗口(双缓冲核心:一次性绘制,解决闪烁)
            g.drawImage(img,0,0,null);

            // 7. 线程休眠1ms:控制刷新频率(约1000fps,可调整为10ms优化性能)
            try {
                Thread.sleep(1);
            }catch (InterruptedException e){
                throw new RuntimeException(e); // 中断异常抛出运行时异常
            }
        }
    }
}

关键注意点

  1. 双缓冲机制:通过BufferedImage创建缓冲图像,先在缓冲中完成所有绘制,再一次性绘制到窗口,彻底解决GUI绘制闪烁问题;
  2. 线程安全:droneListintruderList被多线程共享(UI线程添加元素,DroneThread读取元素),当前未加锁,高并发下可能出现ConcurrentModificationException,需后续添加Collections.synchronizedListReentrantLock
  3. 像素扫描:雷达扫描通过遍历像素颜色实现,需添加像素坐标边界校验,避免超出图像范围导致空指针;
  4. 性能优化:当前休眠1ms(1000fps)性能消耗较大,可调整为10ms(100fps),视觉效果无差异;扫描逻辑仅遍历第一个无人机,可扩展为遍历所有无人机;
  5. 扫描逻辑:通过灰度值判断黑色入侵者,需确保入侵者颜色与背景颜色差异明显,避免误判。

五、UI窗口类:DroneUI(程序入口)

负责创建窗口、初始化组件、关联集合与线程,是程序的入口点。

java 复制代码
package duoxiancheng.xq0122.dronev2;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

/**
 * @author xuqiang
 * @date 2026/1/22  18:53
 * @description UI窗口类:程序入口,负责窗口初始化、组件创建、对象关联
 */
public class DroneUI extends JFrame {
    // 共享集合:存储所有无人机和入侵者(UI、监听器、线程共享同一集合)
    ArrayList<Drone> droneList = new ArrayList<>();
    ArrayList<Intruder> intruderList = new ArrayList<>();

    // 构造方法:初始化窗口和组件
    public DroneUI(){
        setTitle("智能无人机平台"); // 窗口标题
        setSize(1200,1000); // 窗口大小(与绘制缓冲区匹配)
        setDefaultCloseOperation(EXIT_ON_CLOSE); // 关闭窗口退出程序
        setLocationRelativeTo(null); // 窗口居中显示

        // 1. 创建底部按钮面板
        JPanel btnPanel = new JPanel();
        btnPanel.setBackground(Color.LIGHT_GRAY); // 灰色背景

        // 2. 创建"生产无人机"按钮
        JButton createDroneBtn = new JButton("生产无人机");
        btnPanel.add(createDroneBtn);

        // 3. 创建"生产入侵者"按钮(注意:按钮文本与监听器命令一致)
        JButton createIntryderBtn = new JButton("生产入侵者");
        btnPanel.add(createIntryderBtn);

        // 4. 添加按钮面板到窗口底部(BorderLayout.SOUTH)
        add(btnPanel,BorderLayout.SOUTH);
        setVisible(true); // 显示窗口(必须在组件添加后调用)

        // 5. 获取窗口绘图上下文(用于线程绘制)
        Graphics g = this.getGraphics();

        // 6. 初始化线程和监听器
        DroneThread dt = new DroneThread(g); // 传入绘图上下文
        DroneListener droneL = new DroneListener(); // 事件监听器

        // 7. 为按钮绑定监听器
        createDroneBtn.addActionListener(droneL);
        createIntryderBtn.addActionListener(droneL);

        // 8. 注入共享集合(关键:确保所有组件操作同一集合)
        droneL.droneList = droneList;
        dt.droneList = droneList;
        droneL.intruderList = intruderList;
        dt.intruderList = intruderList;

        // 9. 启动后台线程(开始绘制和运动更新)
        dt.start();
    }

    // 重写paint方法:保留父类绘制逻辑(避免窗口刷新异常)
    @Override
    public void paint(Graphics g){
        super.paint(g); // 必须调用父类方法,否则组件(如按钮)无法显示
    }

    // 程序入口:main方法
    public static void main(String[] args){
        new DroneUI(); // 创建UI对象,启动程序
    }
}

关键注意点

  1. 集合共享:droneListintruderList在UI类中初始化,然后注入到监听器和线程中,确保所有组件操作同一集合,数据一致;
  2. 窗口显示:setVisible(true)必须在组件添加后调用,否则组件无法显示;
  3. 绘图上下文:this.getGraphics()获取窗口的绘图上下文,用于线程绘制,需注意窗口大小变化时可能需要重新获取;
  4. paint方法:重写时必须调用super.paint(g),否则父类的组件绘制逻辑会被覆盖,导致按钮等组件无法显示;
  5. 按钮文本:按钮文本必须与监听器中的actionCommand一致(如"生产入侵者"),否则监听器无法识别事件;
  6. 线程启动:dt.start()启动线程,开始后台循环,需确保在所有依赖对象(集合、绘图上下文)注入后调用。

六、整体架构与扩展建议

1. 架构总结

  • 实体层:DroneIntruder封装核心属性和行为;
  • 控制层:DroneThread负责后台逻辑(绘制、运动、扫描);
  • 交互层:DroneListener处理用户输入,DroneUI提供可视化界面;
  • 数据共享:通过ArrayList实现跨组件数据共享,核心是"同一集合注入所有组件"。

2. 优化扩展方向

  1. 线程安全:为共享集合添加同步机制(Collections.synchronizedListLock);
  2. 速度优化:避免速度为0,修改随机逻辑为speedx = random.nextInt(4) - 2; if(speedx ==0) speedx=1;
  3. 攻击逻辑:扩展无人机攻击功能,碰撞检测后减少入侵者血量;
  4. 状态扩展:利用Dronestate属性,实现巡逻、战斗、返航等状态切换;
  5. 性能优化:减少雷达扫描的像素遍历范围,或使用碰撞检测算法(如矩形交集)替代像素扫描;
  6. 界面优化:添加血量显示、无人机数量统计、暂停/继续按钮等。
相关推荐
三伏5222 小时前
Cortex-M3权威指南Cn第七章——笔记
笔记·cortex-m3
丝斯20112 小时前
AI学习笔记整理(56)——大模型微调
人工智能·笔记·学习
whale fall2 小时前
【雅思-口语】与豆包聊天:出国旅游日常聊天英文 + 中文对照合集
笔记·学习·旅游
暴风游侠3 小时前
IDC 学习笔记
笔记·学习
航Hang*3 小时前
计算机等级考试(二级WPS)---第1章:综合应用基础---第1节:WPS公共功能使用
笔记·学习·wps·计算机二级·计算机等级考试
AI视觉网奇3 小时前
https 证书 生成安装笔记
笔记·网络协议·https
myloveasuka3 小时前
3-8 译码器(正式型号74LS138、 74HC138、74HCT138 等))
笔记·算法·计算机组成原理·硬件
myloveasuka3 小时前
MREQ̅ 信号
笔记·算法·计算机组成原理
三伏5223 小时前
Cortex-M3权威指南Cn第八章——笔记
笔记·单片机·嵌入式硬件·cortex-m3