《智能仿真无人机平台(多线程 V4.0)技术笔记》(集群进阶:多无人机任务分配与碰撞规避)

本次实现的是一个具备任务分配、入侵者检测与攻击、自主巡逻功能的智能无人机可视化平台,采用多线程机制保证无人机、任务、入侵者的并发运行。整个项目共包含7个核心类,下面逐类进行详细解析。

1. Drone 类(无人机核心实体)

该类是无人机的实体定义,封装了无人机的位置、速度、尺寸、状态等属性,同时提供了绘制、移动、状态修改的核心方法。
java 复制代码
package duoxiancheng.xq0129.dronev4;
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; // 无人机状态(0=巡逻,1=攻击/任务执行,2=补充弹药)
    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; // 无人机主体固定尺寸30
        this.stateSize=15; // 状态指示灯固定尺寸15
        this.scanSize=100; // 雷达扫描范围固定尺寸100(圆形)
    }

    // 绘制无人机:雷达→主体→状态指示灯,分层绘制实现可视化
    public void drawDrone(Graphics bg) {
        // 1. 绘制半透明蓝色雷达扫描范围(第四个参数60是透明度,实现半透效果)
        Color radarColor = new Color(0, 0, 255, 60);
        bg.setColor(radarColor);
        bg.fillOval(x, y, scanSize, scanSize);

        // 2. 绘制无人机绿色主体(偏移35像素,让主体位于雷达中心)
        Color bodyColor = new Color(64, 195, 66);
        bg.setColor(bodyColor);
        bg.fillOval(x + 35, y + 35, size, size);

        // 3. 绘制状态指示灯,根据state切换颜色(核心:状态与颜色绑定)
        Color stateColor;
        switch (state) {
            case 1: // 攻击状态/任务执行状态 - 红色
                stateColor = Color.RED;
                break;
            case 0: // 巡逻状态 - 黄色
                stateColor = Color.YELLOW;
                break;
            case 2: // 补充弹药状态 - 灰色
                stateColor = Color.GRAY;
                break;
            default: // 默认巡逻状态,防止异常状态无显示
                stateColor = Color.YELLOW;
                break;
        }

        bg.setColor(stateColor);
        bg.fillOval(x + 42, y + 42, stateSize, stateSize); // 偏移42像素,让指示灯位于主体中心
    }

    // 无人机移动方法:边界检测→位置修正→坐标更新,防止卡墙
    public void move() {
        // 1. 先判断边界,反转速度(左右边界200~1000,上下边界175~775)
        boolean hitX = false;
        boolean hitY = false;
        if (x < 200 || (x + scanSize) > 1000) { // 雷达右边界不超过1000,避免超出红色区域
            speedx = -speedx; // 碰到左右边界,横向速度反转
            hitX = true;
        }
        if (y < 175 || (y + scanSize) > 775) { // 雷达下边界不超过775,避免超出红色区域
            speedy = -speedy; // 碰到上下边界,纵向速度反转
            hitY = true;
        }

        // 2. 如果碰到了边界,先修正位置再移动,避免卡墙(核心:边界修正逻辑)
        if (hitX) {
            x = Math.max(200, Math.min(1000 - scanSize, x)); // 强制将x限制在有效区间内
        }
        if (hitY) {
            y = Math.max(175, Math.min(775 - scanSize, y)); // 强制将y限制在有效区间内
        }

        // 3. 更新坐标,实现移动
        x += speedx;
        y += speedy;
    }

    // 新增:方便外部修改无人机状态的方法(提供状态设置入口,解耦外部调用)
    public void setState(int state) {
        this.state = state;
    }

    // 新增:获取当前状态的方法(提供状态查询入口,支持外部逻辑判断)
    public int getState() {
        return this.state;
    }
}

Drone 类关键点

  1. 属性封装:包含位置(x/y)、速度(speedx/speedy)、尺寸(size/scanSize)、状态(state)三大类核心属性,尺寸相关属性在构造方法中默认赋值,保证一致性。
  2. 分层绘制 :按照「雷达→主体→状态指示灯」的层级绘制,雷达设置半透明效果,状态指示灯根据state值切换颜色,实现状态可视化区分。
  3. 安全移动 :包含边界检测、位置修正、坐标更新三步逻辑,Math.max()Math.min()结合避免无人机卡墙,提升运行流畅性。
  4. 状态访问器 :提供setState()getState()方法,封装state属性的读写,符合面向对象封装原则,方便外部类(如TaskThread)进行状态控制。
  5. 坐标偏移:无人机主体和指示灯通过坐标偏移实现居中显示,让可视化效果更规整。

2. Intruder 类(入侵者核心实体)

该类是入侵者的实体定义,封装了入侵者的位置、速度、尺寸、血量等属性,提供绘制和移动方法,同时支持血量可视化与死亡判定。
java 复制代码
package duoxiancheng.xq0129.dronev4;
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; // 入侵者血量(100为满血,≤0为死亡)
    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=45; // 入侵者主体固定尺寸45,不依赖传入参数
        this.blood=100; // 满血初始化为100
    }

    // 绘制入侵者:主体→血条,死亡后不进行绘制(核心:血量判定与可视化)
    public void drawIntruder(Graphics g){
        if(blood <= 0){ // 血量≤0判定为死亡,不绘制任何内容
            return;
        }
        // 1. 绘制入侵者黑色主体
        g.setColor(Color.BLACK);
        g.fillOval(x,y,size,size);
        // 2. 绘制红色边框,增强辨识度
        g.setColor(Color.RED);
        g.drawOval(x-1,y-1,size+2,size+2);

        // 3. 绘制血条背景(红色)
        g.setColor(Color.RED);
        g.fillRect(x,y+size+5,size,6);

        // 4. 绘制当前血量(绿色),按比例计算血条宽度(核心:血量比例换算)
        int bloodWidth = (int)((blood/100.0)*size); // 满血对应血条宽度=入侵者尺寸
        g.setColor(Color.GREEN);
        g.fillRect(x,y+size+5,bloodWidth,6);
    }
    
    // 入侵者移动方法:死亡后停止移动,边界检测后速度反转
    public void move(){
        if(blood <= 0){ // 死亡后不再执行移动逻辑,节省资源
            return;
        }

        // 边界检测:整体窗口范围(5~1200,25~950),碰到边界反转速度
        if(x < 5 || (x+size+5) > 1200){
            speedx = -speedx;
        }
        if(y < 25 || (y+size+5) > 950){
            speedy = -speedy;
        }

        // 更新坐标,实现移动
        x += speedx;
        y += speedy;
    }
}

Intruder 类关键点

  1. 血量机制 :初始血量为100,blood≤0时判定为死亡,停止绘制和移动,减少无效计算。
  2. 血条可视化 :采用「红色背景+绿色当前血量」的双层血条设计,通过(blood/100.0)*size实现血量与血条宽度的比例换算,直观展示入侵者存活状态。
  3. 独立边界 :入侵者的移动边界为整个窗口(51200,25950),与无人机的有效区域(2001000,175775)区分,符合业务逻辑。
  4. 固定尺寸 :入侵者主体尺寸固定为45,构造方法中忽略传入的size参数,保证所有入侵者可视化效果一致。
  5. 边框增强:在主体外围绘制红色边框,提升入侵者在窗口中的辨识度,方便观察无人机与入侵者的交互。

3. Task 类(任务核心实体)

该类是任务的实体定义,封装了任务的位置、状态、血量等属性,提供绘制方法与属性访问器/修改器,支持任务的分配、执行与完成判定。
java 复制代码
package duoxiancheng.xq0129.dronev4;

import java.awt.*;

/**
 * @author xuqiang
 * @date 2026/1/29  16:29
 * @description 任务实体类,封装属性与绘制方法,支持任务生命周期管理
 */
public class Task {
    int x; // 任务坐标(左上角)
    int y; // 任务坐标(左上角)
    int state; // 任务状态(0=未分配,1=已分配,2=已完成)
    int blood; // 任务血量(1为初始,≤0为完成)

    // 构造方法:初始化任务坐标与状态,默认血量为1
    public Task(int x, int y, int state) {
        this.x = x;
        this.y = y;
        this.state = state;
        this.blood = 1; // 任务初始血量为1,扣至≤0即完成
    }

    // 绘制任务:完成后标记状态为2并停止绘制,未完成绘制黑色圆形
    public void draw(Graphics g){
        if(blood <= 0){ // 任务血量≤0判定为完成,标记状态为2并停止绘制
            this.state = 2;
            return;
        }
        // 绘制任务黑色圆形主体,尺寸40
        g.setColor(Color.BLACK);
        g.fillOval(x,y,40,40);
    }

    // 属性访问器与修改器:封装所有属性,提供外部读写入口(符合面向对象封装原则)
    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public int getBlood() {
        return blood;
    }

    public void setBlood(int blood) {
        this.blood = blood;
    }
}

Task 类关键点

  1. 任务生命周期 :通过state属性管理任务的三个状态(0=未分配、1=已分配、2=已完成),通过blood属性控制任务完成条件,形成「创建→分配→执行→完成」的完整生命周期。
  2. 简化完成逻辑 :任务初始血量为1,blood≤0时自动标记为已完成(state=2),停止绘制,逻辑简洁高效。
  3. 完整访问器 :为所有属性提供getXXX()setXXX()方法,封装属性读写,方便TaskThread进行任务状态与血量的修改和查询。
  4. 固定可视化:未完成的任务绘制为40尺寸的黑色圆形,样式统一,方便无人机识别与追踪。
  5. 坐标绑定:任务坐标通过鼠标点击传入,限定在无人机有效区域内,保证任务的可执行性。

4. DroneUI 类(窗口界面核心,程序入口)

该类是整个平台的窗口界面载体,基于Swing的JFrame实现,负责初始化窗口、创建组件、管理集合、绑定监听器与启动多线程,是程序的入口与核心调度者。
java 复制代码
package duoxiancheng.xq0129.dronev4;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

/**
 * @author xuqiang
 * @date 2026/1/22  18:53
 * @description 窗口界面类,程序入口,负责界面初始化、组件绑定与线程启动
 */
public class DroneUI extends JFrame {
    // 三大核心集合:管理所有无人机、入侵者、任务(全局共享,供多线程访问)
    ArrayList<Drone> droneList = new ArrayList<>();
    ArrayList<Intruder> intruderList = new ArrayList<>();
    ArrayList<Task> taskList = new ArrayList<>();// 任务集合,存储所有创建的任务
    
    public DroneUI(){
        // 1. 窗口基础配置(标题、尺寸、关闭方式、居中显示)
        setTitle("智能无人机平台");
        setSize(1200,1000);
        setDefaultCloseOperation(EXIT_ON_CLOSE); // 关闭窗口时退出整个程序
        setLocationRelativeTo(null); // 窗口居中显示

        // 2. 底部按钮面板创建(存放生产无人机、入侵者按钮)
        JPanel btnPanel = new JPanel();
        btnPanel.setBackground(Color.LIGHT_GRAY);

        JButton createDroneBtn = new JButton("生产无人机");
        btnPanel.add(createDroneBtn);

        JButton createIntryderBtn = new JButton("生产入侵者");
        btnPanel.add(createIntryderBtn);

        // 3. 面板布局:按钮面板放在窗口底部(BorderLayout.SOUTH)
        add(btnPanel,BorderLayout.SOUTH);
        setVisible(true); // 显示窗口
        Graphics g = this.getGraphics(); // 获取窗口绘图上下文,供线程绘制使用

        // 4. 多线程创建:无人机线程(负责绘制与交互)、任务线程(负责任务分配与执行)
        DroneThread dt = new DroneThread(g);
        TaskThread tpt = new TaskThread();// 任务线程,处理任务相关逻辑

        // 5. 监听器创建与绑定:绑定按钮事件与鼠标点击事件
        DroneListener droneL = new DroneListener();
        droneL.taskList = taskList;// 给监听器注入任务集合,支持鼠标创建任务

        createDroneBtn.addActionListener(droneL); // 绑定「生产无人机」按钮点击事件
        createIntryderBtn.addActionListener(droneL); // 绑定「生产入侵者」按钮点击事件

        this.addMouseListener(droneL);// 绑定窗口鼠标点击事件,支持创建任务

        // 6. 集合注入:将全局集合注入到监听器与线程中,实现数据共享(核心:多线程数据共享)
        droneL.droneList = droneList;
        dt.droneList = droneList;
        droneL.intruderList = intruderList;
        dt.intruderList = intruderList;
        dt.taskList = taskList;

        tpt.droneList = droneList;// 任务线程注入无人机集合
        tpt.taskList = taskList;// 任务线程注入任务集合

        // 7. 启动多线程:开始执行无人机逻辑与任务逻辑
        dt.start();
        tpt.start();// 启动任务线程
    }
    
    // 重写paint方法:调用父类paint方法,保证窗口重绘时的基础渲染(避免窗口闪烁)
    public void paint(Graphics g){
        super.paint(g);
    }

    // 程序主方法:入口函数,创建DroneUI实例启动程序
    public static void main(String[] args){
        new DroneUI();
    }
}

DroneUI 类关键点

  1. 全局集合管理 :创建droneListintruderListtaskList三个ArrayList集合,用于存储所有无人机、入侵者、任务,为多线程数据共享提供载体。
  2. 界面布局 :采用BorderLayout布局,底部创建灰色按钮面板,存放「生产无人机」和「生产入侵者」两个功能按钮,界面简洁清晰。
  3. 多线程调度 :创建DroneThread(无人机线程)和TaskThread(任务线程),并完成集合注入,最终调用start()方法启动线程,实现并发逻辑。
  4. 监听器绑定 :创建DroneListener监听器,绑定按钮点击事件与鼠标点击事件,同时注入全局集合,实现「生产实体」与「创建任务」的功能触发。
  5. 窗口基础配置 :设置窗口标题、尺寸、关闭方式与居中显示,获取窗口绘图上下文供线程使用,重写paint()方法保证窗口重绘稳定性。
  6. 程序入口main()方法中直接创建DroneUI实例,启动整个平台,无需额外配置,运行便捷。

5. DroneListener 类(事件监听器,处理用户交互)

该类实现了ActionListenerMouseListener接口,负责处理用户的按钮点击事件(生产无人机、入侵者)与鼠标点击事件(创建任务),是用户与程序的交互桥梁。
java 复制代码
package duoxiancheng.xq0129.dronev4;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Random;

/**
 * @author xuqiang
 * @date 2026/1/22  16:32
 * @description 事件监听器类,处理按钮点击与鼠标点击事件,实现用户交互
 */
public class DroneListener implements ActionListener, MouseListener {
    ArrayList<Drone> droneList; // 无人机集合,接收外部注入
    ArrayList<Intruder> intruderList; // 入侵者集合,接收外部注入
    ArrayList<Task> taskList; // 任务集合,接收外部注入
    Random random = new Random(); // 随机数生成器,用于生成随机坐标与速度

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

        if(ac.equals("生产无人机")){
            // 1. 生成无人机随机坐标:限定在无人机有效区域(200~900,175~675)
            int x = 200+random.nextInt(700);
            int y = 175+random.nextInt(500);
            // 2. 生成随机速度(-2~2)
            int speedx = random.nextInt(5)-2;
            int speedy = random.nextInt(5)-2;

            // 3. 保证速度非0:避免无人机静止不动(核心:防止无效无人机)
            while (true){
                if(speedx != 0 || speedy != 0){
                    break;
                }
                speedx = random.nextInt(5)-2;
                speedy = random.nextInt(5)-2;
            }

            // 4. 创建无人机实例,加入无人机集合(初始状态0=巡逻)
            Drone drone = new Drone(x,y,0,speedx,speedy);
            droneList.add(drone);
        }else if(ac.equals("生产入侵者")){
            // 1. 生成入侵者随机坐标:窗口全局范围
            int x = random.nextInt(1150)+5;
            int y = random.nextInt(879)+25;
            int intruderSize = 45;

            // 2. 保证入侵者不在无人机有效区域内:避免初始就被无人机攻击(核心:业务逻辑隔离)
            while (true){
                if(x + intruderSize <= 200 || x>=1000 || y+intruderSize <= 175 || y>=775){
                    break;
                }
                x = random.nextInt(1150)+5;
                y = random.nextInt(879)+25;
            }
            // 3. 生成随机速度(-2~2)
            int speedx = random.nextInt(5)-2;
            int speedy = random.nextInt(5)-2;

            // 4. 保证速度非0:避免入侵者静止不动
            while (true) {
                if (speedx != 0 || speedy != 0) {
                    break;
                }
                speedx = random.nextInt(5) - 2;
                speedy = random.nextInt(5) - 2;
            }

            // 5. 创建入侵者实例,加入入侵者集合
            Intruder itd = new Intruder(x,y,speedx,speedy,intruderSize);
            intruderList.add(itd);
        }
    }

    // 鼠标点击事件:未实现(本次使用鼠标按下事件创建任务)
    @Override
    public void mouseClicked(MouseEvent e) {

    }

    @Override
    public void mousePressed(MouseEvent e) {// 鼠标按下事件:创建任务(核心:任务创建逻辑)
        int x = e.getX(); // 获取鼠标点击横坐标
        int y = e.getY(); // 获取鼠标点击纵坐标

        // 1. 限定任务创建区域:无人机有效区域内,避免无效任务
        if (x >= 200 && x <= 1000 - 40 && y >= 175 && y <= 775 - 40) {
            // 2. 创建未分配状态(state=0)的任务,与业务逻辑一致
            Task task = new Task(x,y,0);
            taskList.add(task);
            System.out.println("生成任务:(" + x + "," + y + ")"); // 控制台打印,方便调试
        }
    }

    // 鼠标释放事件:未实现
    @Override
    public void mouseReleased(MouseEvent e) {

    }

    // 鼠标进入窗口事件:未实现
    @Override
    public void mouseEntered(MouseEvent e) {

    }

    // 鼠标退出窗口事件:未实现
    @Override
    public void mouseExited(MouseEvent e) {

    }
}

DroneListener 类关键点

  1. 双接口实现 :同时实现ActionListener(处理按钮事件)和MouseListener(处理鼠标事件),统一管理用户交互,简化代码结构。
  2. 无人机生产逻辑 :随机生成有效区域内的坐标与非0速度,初始状态为巡逻(state=0),创建后加入droneList集合,保证无人机可被线程调度。
  3. 入侵者生产逻辑 :随机生成全局坐标,且保证初始不在无人机有效区域内,生成非0速度,创建后加入intruderList集合,实现业务逻辑隔离。
  4. 任务创建逻辑 :通过mousePressed()事件触发,限定在无人机有效区域内创建未分配任务(state=0),控制台打印调试信息,方便追踪任务创建情况。
  5. 非0速度保证 :通过while循环过滤速度全为0的情况,避免无人机或入侵者静止不动,保证程序运行的有效性。
  6. 区域限定:所有实体的创建都做了区域限定,避免无效实体创建,提升程序的稳定性与业务合理性。

6. DroneThread 类(无人机核心线程,处理绘制、移动与交互)

该类是核心业务线程,继承Thread类,负责无人机、入侵者、任务的绘制,无人机与入侵者的交互,无人机碰撞检测,以及画面的刷新,是程序可视化与业务交互的核心。
java 复制代码
package duoxiancheng.xq0129.dronev4;

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; // 无人机集合,接收外部注入
    ArrayList<Intruder> intruderList; // 入侵者集合,接收外部注入
    ArrayList<Task> taskList;// 任务集合,接收外部注入
    Graphics g; // 窗口绘图上下文,用于最终画面绘制

    // 构造方法:传入窗口绘图上下文
    public DroneThread(Graphics g){
        this.g=g;
    }

    public void run(){
        // 无限循环:保证线程持续运行,实现实时刷新
        while (true) {
            // 1. 创建缓冲图片:双缓冲技术,避免窗口闪烁(核心:解决界面闪烁问题)
            BufferedImage img = new BufferedImage(1200,950,2);
            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. 绘制并移动所有无人机
            for (int j = 0; j < droneList.size(); j++) {
                Drone drone = droneList.get(j);
                drone.drawDrone(bg);
                drone.move();
            }

            // 4. 绘制所有任务
            for (int i = 0; i < taskList.size(); i++) {
                Task t = taskList.get(i);
                t.draw(bg);
            }// 任务绘制,与无人机绘制分离,逻辑清晰

            // 5. 绘制并移动所有入侵者
            for (int i = 0; i < intruderList.size(); i++) {
                Intruder intruder = intruderList.get(i);
                intruder.drawIntruder(bg);
                intruder.move();
            }

            // 6. 无人机雷达扫描入侵者:检测到后调整方向并切换攻击状态(核心:无人机与入侵者交互逻辑)
            if(droneList.size()>0){
                for (int k = 0; k < droneList.size(); k++) {
                    Drone drone = droneList.get(k);

                    // 遍历无人机雷达范围内的所有像素点
                    for (int i = drone.x; i < drone.x+ drone.scanSize ; i++) {
                        for(int j = drone.y;j < drone.y + drone.scanSize;j++) {

                            // 限定在有效区域内,避免无效扫描
                            if(i<=1000 && i>=200 && j<=775 && j>=175) {
                                int colorNum = img.getRGB(i, j);
                                Color c = new Color(colorNum);
                                // 检测黑色像素(入侵者主体),判定为扫描到入侵者
                                if((c.getRed()+c.getBlue()+c.getGreen())/3 < 10){
                                    // 遍历入侵者,确认扫描到的有效入侵者(满血)
                                    for (int l = 0; l < intruderList.size(); l++) {
                                        Intruder itr = intruderList.get(l);
                                        if(itr.blood > 0 && i<itr.x+itr.size && i>=itr.x && j<itr.y+itr.size && j>= itr.y){

                                            // 计算无人机到入侵者的方向向量
                                            int dx = itr.x - drone.x;
                                            int dy = itr.y - drone.y;
                                            double distance = Math.sqrt(dx*dx + dy*dy);
                                            if (distance > 0) {
                                                // 归一化方向向量,再乘以固定速度3,调整无人机移动方向
                                                drone.speedx = (int) (dx / distance * 3);
                                                drone.speedy = (int) (dy / distance * 3);
                                                // 巡逻状态切换为攻击状态
                                                if (drone.getState() == 0) {
                                                    drone.setState(1);
                                                }
                                            }
                                            break; // 找到对应入侵者后跳出循环,提升效率
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // 7. 无人机状态优先级更新:任务>入侵者>巡逻(核心:状态优先级逻辑)
            for (Drone d : droneList) {// 遍历所有无人机,更新状态
                // 第一步:判断是否有未完成的已分配任务(优先级最高)
                boolean hasUnfinishedTask = false;
                for (Task task : taskList) {
                    if (task.getState() == 1 && task.getBlood() > 0) {
                        int disToTask = (int) Math.sqrt((task.getX() - d.x) * (task.getX() - d.x) + (task.getY() - d.y) * (task.getY() - d.y));
                        if (disToTask <= 125) { // 任务追踪范围125像素
                            hasUnfinishedTask = true;
                            break;
                        }
                    }
                }

                // 第二步:如果没有任务,再判断是否有有效入侵者
                boolean hasValidIntruder = false;
                if (!hasUnfinishedTask) {
                    for (Intruder intruder : intruderList) {
                        if (intruder.blood > 0) {
                            int dis = (int) Math.sqrt((d.x - intruder.x) * (d.x - intruder.x) + (d.y - intruder.y) * (d.y - intruder.y));
                            if (dis <= 100) { // 入侵者检测范围100像素
                                hasValidIntruder = true;
                                break;
                            }
                        }
                    }
                }

                // 第三步:根据优先级更新状态
                if (hasUnfinishedTask) {
                    d.setState(1); // 保留任务执行状态
                } else if (hasValidIntruder) {
                    d.setState(1); // 无任务,有入侵者,进入攻击状态
                } else {
                    d.setState(0); // 无任务无入侵者,恢复巡逻状态
                }
            }// 状态更新逻辑结束

            // 8. 入侵者扣血逻辑:被攻击状态无人机扫描到后扣血(核心:入侵者血量消耗逻辑)
            for (int i = 0; i < intruderList.size(); i++) {
                Intruder intruder = intruderList.get(i);
                if (intruder.blood <= 0){
                    continue;
                }

                boolean flag = false;

                // 遍历入侵者主体像素点,检测是否被无人机扫描
                for (int j = intruder.x; j < intruder.x+45 ; j++) {
                    for (int k = intruder.y; k < intruder.y+45 ; k++) {
                        int colorNum = img.getRGB(j,k);
                        Color c = new Color(colorNum);
                        int gray = (c.getBlue()+c.getRed()+c.getGreen())/3;
                        // 检测无人机绿色主体像素,判定为被无人机扫描
                        if(gray<200 && gray>0 && c.getRed()<150){
                            flag = true;
                            break;
                        }
                    }
                    if(flag){
                        break;
                    }
                }
                if(flag && intruder.blood > 0){
                    // 确认有攻击状态的无人机在攻击范围内
                    boolean isAttacking = false;
                    for (Drone d : droneList) {
                        if (d.getState() == 1) {
                            int dis = (int) Math.sqrt((d.x - intruder.x) * (d.x - intruder.x) + (d.y - intruder.y) * (d.y - intruder.y));
                            if (dis <= 100) { // 攻击范围100像素内
                                isAttacking = true;
                                break;
                            }
                        }
                    }
                    if(isAttacking){
                        intruder.blood--; // 每帧扣1血,实现血量持续消耗
                    }
                }
            }

            // 9. 无人机碰撞检测:避免无人机重叠(核心:碰撞检测与分离逻辑)
            if (droneList.size() > 1) {
                for (int i = 0; i < droneList.size(); i++) {
                    Drone d1 = droneList.get(i);
                    for (int j = i + 1; j < droneList.size(); j++) {
                        Drone d2 = droneList.get(j);

                        // 判定是否碰撞(距离<50)
                        if (Math.abs(d1.x - d2.x) < 50 && Math.abs(d1.y - d2.y) < 50) {
                            // 轻微推开:每次只移1,避免碰撞后弹开幅度过大
                            d1.x += d1.x > d2.x ? 1 : -1;
                            d1.y += d1.y > d2.y ? 1 : -1;
                            d2.x -= d1.x > d2.x ? 1 : -1;
                            d2.y -= d1.y > d2.y ? 1 : -1;
                            // 边界保护:推开后仍限定在有效区域内
                            d1.x = Math.max(200, Math.min(1000 - 100, d1.x));
                            d1.y = Math.max(175, Math.min(775 - 100, d1.y));
                            d2.x = Math.max(200, Math.min(1000 - 100, d2.x));
                            d2.y = Math.max(175, Math.min(775 - 100, d2.y));
                        }
                    }
                }
            }

            // 10. 绘制缓冲图片到窗口,实现画面刷新
            g.drawImage(img,0,0,null);
            try {
                Thread.sleep(1); // 线程休眠1毫秒,控制刷新帧率,减少资源消耗
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }
        }
    }
}

DroneThread 类关键点

  1. 双缓冲技术 :创建BufferedImage作为缓冲画布,先在缓冲画布上完成所有绘制,再一次性绘制到窗口,彻底解决界面闪烁问题,提升可视化流畅度。
  2. 分层绘制逻辑:按照「背景→无人机→任务→入侵者」的顺序绘制,逻辑清晰,避免绘制覆盖导致的显示异常。
  3. 雷达扫描交互:通过遍历雷达范围内的像素点,检测入侵者的黑色主体,计算方向向量调整无人机移动方向,同时切换攻击状态,实现无人机对入侵者的自动追踪与攻击。
  4. 状态优先级:遵循「任务>入侵者>巡逻」的状态优先级,保证无人机优先执行任务,再处理入侵者,最后恢复巡逻,符合业务逻辑。
  5. 入侵者扣血:检测到无人机绿色主体后,确认攻击状态无人机在攻击范围内,实现入侵者血量持续消耗,直到死亡。
  6. 碰撞检测与分离:检测无人机之间的距离,碰撞后进行轻微推开,并做边界保护,避免无人机重叠与卡墙,提升运行稳定性。
  7. 无限循环与休眠 :通过while(true)保证线程持续运行,Thread.sleep(1)控制刷新帧率,平衡流畅度与资源消耗。

7. TaskThread 类(任务核心线程,处理任务分配与执行)

该类是任务专属线程,继承Thread类,负责任务的自动分配(给最近的巡逻无人机)、无人机对任务的追踪、任务完成判定与无人机状态恢复,是任务生命周期的核心调度者。
java 复制代码
package duoxiancheng.xq0129.dronev4;

import java.util.ArrayList;

/**
 * @author xuqiang
 * @date 2026/1/29  16:34
 * @description 任务核心线程,负责任务分配、追踪与完成判定
 */
public class TaskThread extends Thread {
    ArrayList<Drone> droneList; // 无人机集合,接收外部注入
    ArrayList<Task> taskList; // 任务集合,接收外部注入

    public void run() {
        // 无限循环:持续处理任务相关逻辑
        while (true) {
            try {
                Thread.sleep(30); // 休眠30毫秒,降低任务调度频率,减少资源消耗
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            // 1. 任务自动分配:将未分配任务(state=0)分配给最近的巡逻无人机(核心:任务分配逻辑)
            for (int i = 0; i < taskList.size(); i++) {
                Task t = taskList.get(i);
                if (t.getState() == 0) { // 只处理未分配的任务
                    int min = 1000; // 初始化最小距离为1000(大于最大有效距离)
                    int index = -1; // 初始化目标无人机索引为-1(无有效无人机)

                    // 遍历所有无人机,寻找最近的巡逻状态无人机(state=0)
                    for (int j = 0; j < droneList.size(); j++) {
                        Drone d = droneList.get(j);
                        // 只选择巡逻状态的无人机,不干扰攻击/补给状态的无人机(核心:任务分配约束)
                        if (d.getState() == 0) {
                            int dis = (int) Math.sqrt((t.getX() - d.x) * (t.getX() - d.x) + (t.getY() - d.y) * (t.getY() - d.y));
                            if (dis < min) {
                                min = dis;
                                index = j;
                            }
                        }
                    }
                    // 找到可用无人机后,分配任务并设置追踪速度
                    if (index != -1) {
                        Drone drone = droneList.get(index);
                        // 标记任务为已分配(state=1)、无人机为攻击/任务执行状态(state=1)
                        t.setState(1);
                        drone.setState(1);

                        int dx = t.getX() - drone.x;
                        int dy = t.getY() - drone.y;
                        double distance = Math.sqrt(dx * dx + dy * dy);

                        if (distance > 0) {
                            // 1. 先计算原始的x/y方向速度(未强转,保留小数)
                            double rawSpeedX = (dx / distance) * 3;
                            double rawSpeedY = (dy / distance) * 3;

                            // 2. 独立处理x方向速度:绝对值<1则强制设±1,否则正常强转(核心:解决单一方向卡壳)
                            if (Math.abs(rawSpeedX) < 1) {
                                drone.speedx = dx > 0 ? 1 : (dx < 0 ? -1 : 0);
                            } else {
                                drone.speedx = (int) rawSpeedX;
                            }

                            // 3. 独立处理y方向速度:和x方向逻辑完全一致,彻底解决单一方向卡壳
                            if (Math.abs(rawSpeedY) < 1) {
                                drone.speedy = dy > 0 ? 1 : (dy < 0 ? -1 : 0);
                            } else {
                                drone.speedy = (int) rawSpeedY;
                            }
                        } else {
                            // 距离为0,已抵达目标,速度置0
                            drone.speedx = 0;
                            drone.speedy = 0;
                        }
                    }
                }
            }

            // 2. 任务完成判定:无人机抵达任务区域后扣减任务血量,完成后恢复无人机巡逻状态(核心:任务完成逻辑)
            if (taskList.size() > 0) {
                for (int i = 0; i < droneList.size(); i++) {
                    Drone d = droneList.get(i);
                    if (d.getState() == 1) { // 只处理攻击/任务执行状态无人机
                        Task targetTask = null;
                        int min = 1000;

                        // 第一步:找到当前无人机最近的、已分配的任务(专属目标)
                        for (int j = 0; j < taskList.size(); j++) {
                            Task t = taskList.get(j);
                            if (t.getState() == 1) {
                                int dx = t.getX() - d.x;
                                int dy = t.getY() - d.y;
                                int dis = (int) Math.sqrt(dx * dx + dy * dy);
                                if (dis < min) {
                                    min = dis;
                                    targetTask = t;
                                }
                            }
                        }

                        // 第二步:只处理专属目标,判断是否抵达并扣血
                        if (targetTask != null) {
                            int droneCenterX = d.x + d.scanSize / 2; // 无人机中心坐标(雷达中心)
                            int droneCenterY = d.y + d.scanSize/ 2;
                            int targetCenterX = targetTask.getX() + 20; // 任务中心坐标
                            int targetCenterY = targetTask.getY() + 20;

                            // 计算圆心距离的平方(避免开方,提升性能)
                            double dx = droneCenterX - targetCenterX;
                            double dy = droneCenterY - targetCenterY;
                            double distanceSquard = dx * dx + dy * dy;

                            // 雷达半径50 + 目标半径20,平方后为70*70=4900(攻击范围判定)
                            boolean inAttackRange = distanceSquard <= 4900;
                            if (inAttackRange) {
                                d.speedx = 0;
                                d.speedy = 0; // 抵达任务区域后停止移动
                                targetTask.setBlood(targetTask.getBlood() - 1); // 扣减任务血量

                                // 任务血量为0,标记完成并恢复无人机巡逻状态
                                if (targetTask.getBlood() <= 0) {
                                    targetTask.setState(2);
                                    d.setState(0);
                                    // 重置巡逻随机速度,确保非0(与生产无人机时逻辑一致)
                                    do {
                                        d.speedx = (int) (Math.random() * 5 - 2);
                                        d.speedy = (int) (Math.random() * 5 - 2);
                                    } while (d.speedx == 0 && d.speedy == 0);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

TaskThread 类关键点

  1. 任务自动分配 :只将未分配任务(state=0)分配给最近的巡逻无人机(state=0),不干扰其他状态的无人机,保证分配的合理性与高效性。
  2. 防卡壳速度计算:独立处理x、y方向速度,绝对值<1时强制设为±1,解决无人机在单一方向上无法移动的卡壳问题,提升任务追踪的流畅性。
  3. 专属目标追踪:为每个无人机匹配最近的已分配任务作为专属目标,避免多无人机争抢同一个任务,提升任务执行效率。
  4. 高效距离判定:使用圆心距离的平方进行攻击范围判定,避免开方运算,提升程序运行性能。
  5. 任务完成与状态恢复 :任务完成后,自动将无人机状态恢复为巡逻(state=0),并重置随机非0速度,让无人机回归正常巡逻,形成任务执行的闭环。
  6. 低频率调度:线程休眠30毫秒,降低任务调度频率,在保证任务响应性的同时,减少系统资源消耗。

总结

  1. 技术亮点:双缓冲技术解决界面闪烁、状态优先级保证业务逻辑、防卡壳速度计算提升流畅性、碰撞检测避免实体重叠。
  2. 关键业务闭环:(各实体生命周期完整)
无人机【巡逻→任务/入侵者响应→执行→恢复巡逻】
任务【创建→分配→执行→完】
入侵者【创建→被攻击→死亡】
相关推荐
ruxshui3 小时前
个人笔记: 星环Inceptor/hive普通分区表与范围分区表核心技术总结
hive·hadoop·笔记
慾玄3 小时前
渗透笔记总结
笔记
CS创新实验室4 小时前
关于 Moltbot 的学习总结笔记
笔记·学习·clawdbot·molbot
Q_21932764554 小时前
车灯控制与报警系统设计
人工智能·嵌入式硬件·无人机
Deepoch4 小时前
Deepoc具身模型外拓板:重塑无人机作业逻辑,开启行业智能新范式
科技·机器人·无人机·开发板·黑科技·具身模型·deepoc
Yuroo zhou5 小时前
IMU如何成为机器人自主移动的核心传感器
人工智能·机器人·无人机·导航·传感器·飞行器
孞㐑¥5 小时前
算法—分治
开发语言·c++·经验分享·笔记·算法
我命由我123455 小时前
Git 初始化本地仓库并推送到远程仓库解读
运维·服务器·经验分享·笔记·git·学习·学习方法
Aliex_git5 小时前
Claude Code 使用笔记(四)- GitHub Claude 审查助手
人工智能·笔记·学习·github·ai编程