Java编程进阶:智能仿真无人机项目3.0

一、项目前期准备

V3 版本在 V2 基础上聚焦了双向交互与智能对抗,新增 "双向扫描""目标锁定""攻击扣血" 核心逻辑,新手需在 V2 基础(集合、事件监听、线程通信)上,再额外掌握以下知识点:

1. 双向扫描原理

  • 核心:无人机扫描入侵者、入侵者反向扫描无人机,通过像素颜色检测 + 坐标匹配实现目标识别;
  • 灰度值判断:通过(红+绿+蓝)/3计算像素灰度值,区分深色(入侵者)、中间色(无人机)等目标。

2. 目标锁定与跟随

  • 逻辑:无人机扫描到入侵者后,获取其速度参数,同步调整自身速度,实现 "跟随追击";
  • 关键:通过坐标范围匹配(i >= 入侵者 && i < 入侵者x + 尺寸),精准定位扫描到的目标。

3. 攻击扣血机制

  • 核心:扫描到目标后,通过修改目标的 blood 属性(减少生命值)实现攻击效果;
  • 触发条件:满足颜色检测 + 坐标匹配双重验证,避免误攻击。

4. 循环与条件判断进阶

  • 多层嵌套循环:遍历无人机 / 入侵者集合→遍历雷达像素范围→匹配目标坐标;
  • 标志位(flag):控制攻击逻辑的触发与终止,避免重复扣血。

二、项目结构解析

V3 版本的核心变化是实现无人机与入侵者的双向交互,通过 "扫描→锁定→攻击→扣血" 的完整链路,模拟智能防御场景。

1.项目结构分析

类名 作用 核心新增技术点
Drone 无人机实体类(属性 + 绘制 + 移动) 移动边界优化(防止超出防守区)
Intruder 入侵者实体类(属性 + 绘制 + 移动) 边界判断调整(适配新窗口范围)
DroneListener 按钮监听器(生产实体) 入侵者随机坐标范围优化(50~999, 50~849)
DroneThread 核心线程(扫描 + 锁定 + 攻击 + 绘制) 双向扫描、目标锁定、攻击扣血、跟随逻辑
DroneUI 界面搭建(窗口 + 组件 + 共享数据) 保持原有结构,适配 V3 实体类

2.项目核心逻辑流程

用户点击按钮 → 监听器创建Drone/Intruder对象 → 存入共享ArrayList → 无人机线程启动: 1. 遍历集合,调用所有实体的move()和draw()方法; 2. 无人机扫描:遍历雷达像素→颜色检测→坐标匹配入侵者→锁定目标+跟随+扣血; 3. 入侵者扫描:遍历自身扫描范围→颜色检测→坐标匹配无人机→反向扣血; 4. 双缓冲绘制画面→线程休眠→循环执行。

三、核心代码详细讲解

1.实体类 ------Drone类

V3 版本的实体类未改变核心结构,仅优化了边界判断逻辑,确保运动范围更合理,为后续交互提供稳定基础。

(1)关键代码解析
java 复制代码
import java.awt.Graphics;
import java.awt.Color;
 
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.size = 30; // 主体尺寸固定30像素
        this.stateSize = 15; // 状态灯尺寸固定15像素
        this.scanSize = 100; // 雷达范围固定100像素
        this.speedx = speedx;
        this.speedy = speedy;
    }
 
    //绘制无人机
    public void drawDrone(Graphics bg) {
        // 1. 绘制雷达扫描范围
        Color color1 = new Color(0, 0, 255, 60); // RGB:蓝色,透明度60
        bg.setColor(color1);
        bg.fillOval(x, y, scanSize, scanSize); // 雷达范围:100×100像素
 
        // 2. 绘制无人机主体
        Color color2 = new Color(64, 195, 66); // 绿色
        bg.setColor(color2);
        bg.fillOval(x + 35, y + 35, size, size); // 偏移35像素:雷达中心=主体中心
 
        // 3. 绘制状态指示灯
        Color color3 = new Color(255, 0, 0); // 红色
        bg.setColor(color3);
        bg.fillOval(x + 42, y + 42, stateSize, stateSize); // 再偏移7像素,继续居中
    }
 
    //无人机移动
    public void move() {
        if (blood <= 0) {
           return; // 生命值为0时停止移动
        }
        // 边界调整:左30,右1200-70-尺寸,上30,下950-70-尺寸
        // 70是预留安全距离,避免入侵者紧贴窗口边缘
        if (x > 1200 - 70 - size || x < 30) {
           speedx = -speedx;
        }
        if (y > 950 - 70 - size || y < 30) {
           speedy = -speedy;
        }
        x += speedx;
        y += speedy;
    }
}
(2)理解要点

避免无人机因速度过快或边界判断延迟,超出防守区核心范围,保证扫描和攻击逻辑有效。

2.敌对实体类 ------Intruder类

(1)关键代码解析
java 复制代码
import java.awt.Graphics;
import java.awt.Color;
 
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
    }
 
    // 行为1:绘制入侵者
    public void drawIntruder(Graphics g) {
        if (blood <= 0) { // 生命值≤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); // 绘制红色边框
    }
 
    // 行为2:入侵者移动
    public void move() {
        if (blood <= 0) { 
            return;  // 生命值为0时停止移动
        }
        // 边界调整:左30,右1200-70-尺寸,上30,下950-70-尺寸
        // 70是预留安全距离,避免入侵者紧贴窗口边缘
        if (x > 1200 - 70 - size || x < 30) {
            speedx = -speedx;
        }
        if (y > 950 - 70 - size || y < 30) {
            speedy = -speedy;
        }
        x += speedx;
        y += speedy;
    }
}
(2)理解要点

扩大入侵者的运动范围(相比 V2),同时预留安全距离,避免与窗口边缘重叠,提升视觉效果。

3.运动与绘制核心 ------DroneThread

DroneThread 是 V3 版本的核心,新增"了无人机扫描攻击"、"入侵者反向扫描"、"目标锁定跟随" 三大核心逻辑,是智能对抗的实现载体。

(1)关键代码解析
java 复制代码
import java.awt.Graphics;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

public class DroneThread extends Thread {
    ArrayList<Drone> droneList; // 共享无人机集合
    ArrayList<Intruder> intruderList; // 共享入侵者集合
    Graphics g;

    public DroneThread(Graphics g) {
        this.g = g;
    }

    public void run() {
        while (true) { // 死循环:持续交互
            // 1. 双缓冲初始化(避免绘制闪烁,与V2一致)
            BufferedImage img = new BufferedImage(1200, 950, 2);
            Graphics bg = img.getGraphics();
            bg.setColor(Color.WHITE);
            bg.fillRect(0, 0, 1200, 950);
            bg.setColor(Color.RED);
            bg.drawRect(200, 175, 800, 600); // 绘制防守区边框

            // 2. 所有实体移动+绘制(与V2一致)
            // 无人机:绘制→移动
            for (int j = 0; j < droneList.size(); j++) {
                Drone drone = droneList.get(j);
                drone.drawDrone(bg);
                drone.move();
            }
            // 入侵者:移动→绘制
            for (int i = 0; i < intruderList.size(); i++) {
                Intruder intruder = intruderList.get(i);
                intruder.move();
                intruder.drawIntruder(bg);
            }

            // 3. 核心逻辑1:无人机扫描→锁定入侵者→攻击+跟随
            if (droneList.size() > 0) { // 至少有1架无人机才扫描
                // 遍历每一架无人机
                for (int k = 0; k < droneList.size(); k++) {
                    Drone drone = droneList.get(k);
                    // 遍历无人机的雷达范围(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;
                            }
                            // 获取当前像素的颜色,计算灰度值
                            int colorNum = img.getRGB(i, j);
                            Color c = new Color(colorNum);
                            int gray = (c.getRed() + c.getBlue() + c.getGreen()) / 3;

                            // 灰度值<10:检测到深色(入侵者主体是黑色)
                            if (gray < 10) {
                                // 坐标匹配:找到灰度值对应的入侵者对象
                                for (int l = 0; l < intruderList.size(); l++) {
                                    Intruder itr = intruderList.get(l);
                                    // 判断当前像素是否在入侵者的坐标范围内(精准匹配)
                                    if (i >= itr.x && i < itr.x + itr.size && j >= itr.y && j < itr.y + itr.size) {
                                        // 目标锁定+跟随:无人机速度同步入侵者速度
                                        drone.speedx = itr.speedx;
                                        drone.speedy = itr.speedy;
                                        // 攻击:入侵者生命值-1(每扫描到一次扣1血)
                                        itr.blood--;
                                        System.out.println("入侵者被攻击,生命值:" + itr.blood);
                                        break; // 锁定一个目标,避免重复攻击
                                    }
                                }
                            }
                        }
                    }
                }
            }

            // 4. 核心逻辑2:入侵者反向扫描→攻击无人机
            for (int i = 0; i < intruderList.size(); i++) {
                Intruder intruder = intruderList.get(i);
                if (intruder.blood <= 0) {
                    continue; // 生命值为0,不扫描
                }
                boolean flag = false; // 标志位:是否检测到无人机,避免重复扣血
                // 入侵者的扫描范围:x-15到x+70,y-15到y+70(自定义范围)
                for (int j = intruder.x - 15; j < intruder.x + 70; j++) {
                    for (int k = intruder.y - 15; k < intruder.y + 70; k++) {
                        // 避免坐标越界
                        if (j < 0 || j >= 1200 || k < 0 || k >= 950) {
                            continue;
                        }
                        // 获取像素颜色,计算灰度值
                        int colorNum = img.getRGB(j, k);
                        Color c = new Color(colorNum);
                        int gray = (c.getBlue() + c.getRed() + c.getGreen()) / 3;

                        // 灰度值30~150 + 红色值<100:检测到无人机(绿色主体+蓝色雷达)
                        if (gray > 30 && gray < 150 && c.getRed() < 100) {
                            drone.blood--; // 无人机生命值-1(需在Drone类新增blood属性)
                            System.out.println("无人机被攻击,生命值:" + drone.blood);
                            flag = true; // 标记已检测到,跳出循环
                            break;
                        }
                    }
                    if (flag) {
                        break; // 避免同一入侵者多次攻击同一无人机
                    }
                }
            }

            // 5. 移除生命值≤0的实体(避免无效绘制和计算)
            // 移除死亡的入侵者
            for (int i = 0; i < intruderList.size(); i++) {
                if (intruderList.get(i).blood <= 0) {
                    intruderList.remove(i);
                    i--; // 移除后索引前移,避免漏判
                }
            }
            // 移除死亡的无人机(需在Drone类新增blood属性)
            for (int j = 0; j < droneList.size(); j++) {
                if (droneList.get(j).blood <= 0) {
                    droneList.remove(j);
                    j--;
                }
            }

            // 6. 绘制到窗口+线程休眠(与V2一致)
            g.drawImage(img, 0, 0, null);
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
(2)理解要点

无人机扫描攻击流程(3 层循环 + 2 重验证)

  • 外层循环:遍历所有无人机(droneList);
  • 中层循环:遍历当前无人机的雷达范围(drone.xdrone.x+scanSize);
  • 内层循环:遍历雷达范围内的每个像素;
  • 第一重验证:灰度值 < 10(检测到深色像素,可能是入侵者);
  • 第二重验证:坐标匹配(像素坐标在入侵者的x~x+sizey~y+size范围内,确认是入侵者);
  • 执行操作:无人机同步入侵者速度(跟随)、入侵者生命值 - 1(攻击)。

入侵者反向扫描流程(标志位 + 颜色筛选)

  • 外层循环:遍历所有入侵者(intruderList),跳过已死亡的;
  • 中层 + 内层循环:遍历入侵者的自定义扫描范围(x-15x+70);
  • 颜色筛选:灰度值 30~150(中间色)+ 红色值 < 100(排除红色元素),精准匹配无人机(绿色主体 + 蓝色雷达);
  • 标志位flag:避免同一入侵者多次攻击同一无人机,检测到后直接跳出循环。

死亡实体移除逻辑

  • 问题:生命值≤0 的实体若不移除,会持续占用集合资源,导致无效循环;
  • 解决:遍历集合时,移除生命值≤0 的对象,同时索引i--(因为集合长度减少,索引会自动前移,避免漏判下一个元素)

4.交互核心 ------DroneListener类

(1)关键代码解析
java 复制代码
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
 
public class DroneListener implements ActionListener {
    // 共享集合:存储无人机和入侵者
    ArrayList<Drone> droneList;
    ArrayList<Intruder> intruderList;
    Random random = new Random(); // 随机数生成器
 
    // 按钮点击后触发的核心方法
    public void actionPerformed(ActionEvent e) {
        // 获取点击按钮的"指令名称"
        String ac = e.getActionCommand();
 
        // 1. 点击"生产无人机"按钮
        if (ac.equals("生产无人机")) {
            // 生成随机坐标:x在200~899(防守区内),y在175~674
            int x = random.nextInt(700) + 200; // 700是范围(899-200+1),+200是起始值
            int y = random.nextInt(500) + 175; // 500是范围(674-175+1),+175是起始值
            // 生成随机速度:-2~2(左右/上下都能运动)
            int speedx = random.nextInt(5) - 2; // 0~4 → -2~2
            int speedy = random.nextInt(5) - 2;
            // 创建无人机对象
            Drone drone = new Drone(x, y, 0, speedx, speedy);
            // 存入共享集合
            droneList.add(drone);
        }
        // 2. 点击"生产入侵者"按钮
        else if (ac.equals("生产入侵者")) {
            // 生产入侵者:随机坐标范围调整为50~999(x)、50~849(y)
            int x = random.nextInt(950) + 50; // 950=999-50+1,+50是起始值
            int y = random.nextInt(800) + 50; // 800=849-50+1,+50是起始值
            // 坐标校验:确保入侵者初始在防守区外(与V2一致)
            while (true) {
                 if (x < 200 || x > 1000 || y < 175 || y > 775) {
                    break;
                }
                x = random.nextInt(950) + 50;
                y = random.nextInt(800) + 50;
            } 
            // 生成随机速度:-2~2
            int speedx = random.nextInt(5) - 2;
            int speedy = random.nextInt(5) - 2;
            // 创建入侵者对象
            Intruder itd = new Intruder(x, y, speedx, speedy, 45);
            // 存入共享集合
            intruderList.add(itd);
        }
    }
}
(2)理解要点

扩大入侵者初始坐标范围,增加与无人机交互的概率

5.界面搭建与数据共享 ------DroneUI

V3 版本的界面延续了V2版本,无需对代码进行修改,仅需确保Drone类新增blood属性(生命值),否则入侵者反向攻击时会报错。

(1)关键代码
java 复制代码
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
 
public class DroneUI extends JFrame {
    // 共享集合:初始化无人机和入侵者列表
    ArrayList<Drone> droneList = new ArrayList<>();
    ArrayList<Intruder> intruderList = new ArrayList<>();
 
    public DroneUI() {
        // 1. 窗口基础设置
        setTitle("智能无人机平台");
        setSize(1200, 1000); // 窗口宽1200,高1000
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLocationRelativeTo(null); // 居中显示
 
        // 2. 创建按钮面板
        JPanel btnPanel = new JPanel();
        btnPanel.setBackground(Color.LIGHT_GRAY); // 面板灰色背景
        JButton btn = new JButton("生产无人机"); // 按钮1
        JButton btn1 = new JButton("生产入侵者"); // 按钮2
        btnPanel.add(btn); // 按钮加入面板
        btnPanel.add(btn1);
        // 面板放在窗口底部(BorderLayout.SOUTH)
        add(btnPanel, BorderLayout.SOUTH);
 
        // 3. 显示窗口
        setVisible(true);
 
        // 4. 初始化绘图工具、监听器、线程
        Graphics g = this.getGraphics(); // 获取窗口绘图工具
        DroneListener droneL = new DroneListener(); // 创建监听器对象
        DroneThread dt = new DroneThread(g); // 创建无人机线程对象
 
        // 5. 按钮注册监听器
        btn.addActionListener(droneL);
        btn1.addActionListener(droneL);
 
        // 6. 共享集合传递
        droneL.droneList = droneList; // 监听器获取无人机集合
        droneL.intruderList = intruderList; // 监听器获取入侵者集合
        dt.droneList = droneList; // 线程获取无人机集合
        dt.intruderList = intruderList; // 线程获取入侵者集合
 
        // 7. 启动无人机线程
        dt.start();
    }
 
    // 重写paint方法:保证窗口刷新正常
    public void paint(Graphics g) {
        super.paint(g);
    }
 
    // 程序入口:启动项目
    public static void main(String[] args) {
        new DroneUI();
    }
}

四、常见问题与注意事项(新手避坑)

1. 数组下标越界异常(高频问题)

  • 错误现象:img.getRGB(i,j)抛出 ArrayIndexOutOfBoundsException
  • 原因:扫描范围超出画布(1200×950),未做坐标校验;
  • 解决:在获取像素颜色前,添加if (i < 0 || i >= 1200 || j < 0 || j >= 950) continue;

2. 攻击逻辑失效(生命值不变化)

  • 原因 1:颜色筛选条件错误(如灰度值阈值设置不当,未匹配目标颜色);
  • 原因 2:坐标匹配逻辑错误(如i < itr.x写成i <= itr.x,未覆盖入侵者完整范围);
  • 解决:
    1. 调整灰度值阈值(无人机扫描入侵者用gray < 10,入侵者扫描无人机用gray >30 && gray <150);
    2. 确认坐标匹配条件:i >= itr.x && i < itr.x + itr.size(包含左边界,不包含右边界,符合像素坐标逻辑)。

3. 实体移除后出现空指针

  • 错误现象:intruderList.get(i).blood抛出NullPointerException
  • 原因:移除实体时未调整索引(如intruderList.remove(i)后,i--,导致下一次循环访问到null);
  • 解决:移除元素后,索引 i -- 或 j --,确保遍历不跳过元素。

4. 无人机没有生命值属性(编译错误)

  • 错误现象:drone.blood------提示 "无法解析符号 blood";
  • 原因:Drone类未新增 blood 属性和初始化;
  • 解决:按 "模块 4" 的步骤,给Drone类加 blood 属性和构造方法初始化。

五、拓展巩固

1. 优化攻击效率(避免单次扫描多次扣血)

  • 需求:每架无人机每秒仅攻击 1 次入侵者,避免短时间内生命值骤降;
  • 思路:给Drone类添加lastAttackTime属性(记录上次攻击时间),攻击前判断当前时间与上次攻击时间间隔≥1000 毫秒(1 秒)。

2. 实现 "协同围剿"(广播机制)

  • 需求:1 架无人机扫描到入侵者后,通知其他无人机共同追击;
  • 思路:
    1. 新增lockedIntruder属性(Drone类),存储锁定的入侵者对象;
    2. 当 1 架无人机锁定目标后,将lockedIntruder赋值给其他无人机;
    3. 其他无人机直接跟随lockedIntruder的速度,实现协同追击。

3. 添加 "锁定状态" 可视化

  • 需求:无人机锁定入侵者后,入侵者边框变为黄色,直观显示锁定状态;
  • 思路:在 Intruder类的 drawIntruder方法中,添加条件判断:若 blood < 100(被攻击过,即被锁定),绘制黄色边框。

4. 替换硬编码为配置变量

  • 需求:将坐标、尺寸、速度等硬编码数字(如1200"100")替换为常量,提高代码可维护性;
  • 思路:创建Config类,定义静态常量(public static final int WINDOW_WIDTH = 1200;),其他类直接引用Config.WINDOW_WIDTH

六、总结

V3 版本相比 V2,实现了从 "静态实体" 到 "动态交互" 的质变,核心收获如下:

  1. 双向交互逻辑设计:掌握 "扫描→匹配→攻击→反馈" 的完整交互链路,理解如何通过颜色和坐标实现目标识别;
  2. 智能策略落地:学会用 "速度同步" 实现目标跟随,用 "标志位" 控制逻辑触发,用 "协同围剿" 优化对抗效果;
  3. 代码健壮性优化:掌握数组越界防护、实体生命周期管理(移除死亡对象)、硬编码替换等实用技巧;
  4. 面向对象思想深化:实体类仅新增属性和优化方法,核心逻辑封装在线程中,实现 "功能模块化",符合真实项目设计规范。

以上是智能仿真无人机项目3.0的基础功能展示,对于 Java 新手,V3 版本的学习重点是 "多层循环的逻辑控制" 和 "交互场景的拆解"------ 复杂的智能对抗,本质是 "循环遍历 + 条件判断 + 数据修改" 的组合。通过本项目能够巩固多线程、集合、Swing 等基础知识点,同时还能培养 "从需求到代码" 的落地能力,为后续开发小游戏、管理系统等复杂项目打下坚实基础。下一篇我们会升级到V4.0,完善其余功能。如果现在运行代码遇到问题,或者想提前了解V4.0的核心知识点,随时留言告诉我。

相关推荐
是阿楷啊1 小时前
Java求职面试实录:互联网大厂场景技术点解析
java·redis·websocket·spring·互联网·大厂面试·支付系统
_周游2 小时前
Java8 API文档搜索引擎_3.搜索模块(实现细节)
java·搜索引擎·intellij-idea
中屹指纹浏览器2 小时前
指纹浏览器技术落地实践:多场景适配与性能优化全解析
经验分享·笔记
人道领域2 小时前
SSM从入门到入土(Spring Bean实例化与依赖注入全解析)
java·开发语言·spring boot·后端
long3162 小时前
Z算法(线性时间模式搜索算法)
java·数据结构·spring boot·后端·算法·排序算法
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 基于Java web的宠物领养系统的设计与实现为例,包含答辩的问题和答案
java·开发语言·宠物
瑞雪兆丰年兮2 小时前
[从0开始学Java|第十三天]面向对象进阶(static&继承)
java·开发语言
小楼v2 小时前
如何实现AI生成应用部署功能
java·后端·ai·部署
张人玉2 小时前
WPF 多语言实现完整笔记(.NET 4.7.2)
笔记·.net·wpf·多语言实现·多语言适配