引言
在之前的V1、V2版本中,该平台可动态生成我方无人机 与敌方入侵者 ,两者均具备自主移动能力,并能通过像素级扫描互相发现与攻击。V3版本在之前版本基础上优化了边界处理、速度随机生成逻辑,并完善了双向扫描机制(无人机扫描入侵者并跟随,入侵者扫描无人机并扣除生命值)。
项目结构
| 类名 | 类型 | 职责 |
|---|---|---|
Drone |
实体类 | 表示我方无人机,包含位置、速度、扫描范围等属性,提供绘制与移动方法。 |
Intruder |
实体类 | 表示敌方入侵者,包含位置、速度、生命值等属性,提供绘制与移动方法。 |
DroneUI |
界面类 | 继承JFrame,搭建主窗口、按钮面板,并初始化共享数据列表及线程。 |
DroneListener |
监听器类 | 实现ActionListener,响应按钮点击事件,随机生成无人机或入侵者对象并加入列表。 |
DroneThread |
线程类 | 继承Thread,在run()中循环刷新图像,执行所有对象的绘制、移动及双向扫描逻辑。 |
数据共享:
DroneUI中维护两个ArrayList分别存储无人机和入侵者对象,通过引用传递给DroneListener和DroneThread,实现多线程间的数据共享。
项目更新具体实现(聚焦V3版本新增功能)
1.事件监听器:DroneListener
package Dronev3;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Random;
public class DroneListener implements ActionListener {
ArrayList<Intruder> intruderList;
ArrayList<Drone> droneList=new ArrayList<>();
Random random=new Random();
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Drones Production")){
int x= random.nextInt(700)+200;
int y= random.nextInt(500)+175;
int speedx;
do {
speedx = random.nextInt(5) - 2;
} while (speedx == 0);
int speedy;
do {
speedy = random.nextInt(5) - 2;
} while (speedy == 0);
Drone drone=new Drone(x,y,speedx,speedy,0);
droneList.add(drone);
} else if (e.getActionCommand().equals("Intruder Production")) {
int x= random.nextInt(950)+50;
int y= random.nextInt(800)+50;
while (true){
if (x<200 || x>1000 || y<175 || y>775) {
break;
}
x= random.nextInt(950)+50;
y= random.nextInt(800)+50;
}
int speedx;
do {
speedx = random.nextInt(5) - 2;
} while (speedx == 0);
int speedy;
do {
speedy = random.nextInt(5) - 2;
} while (speedy == 0);
Intruder intruder=new Intruder(x,y,speedx,speedy,45,100);
intruderList.add(intruder);
}
}
}
更新解析:
生成无人机 :坐标范围在红色边界框内(x:200~900,y:175~675),使用
nextInt(700)+200和nextInt(500)+175确保。速度通过do-while保证非零(-2,-1,1,2),避免静止对象。生成入侵者 :坐标范围全屏(50~1000,x:50~1000,y:50~850),但要求必须位于红色边界框之外 (即x<200或x>1000或y<175或y>775)。使用
while(true)循环不断生成直到满足条件。速度同样保证非零。2.
2.核心线程:DroneThread
package Dronev3;
import java.awt.*;
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) {
BufferedImage image = new BufferedImage(1200, 950, 2);
Graphics bg = image.getGraphics();
bg.setColor(Color.WHITE);
bg.fillRect(0, 0, 1200, 950);
bg.setColor(Color.RED);
bg.drawRect(200, 175, 800, 600);
// 遍历无人机数组,调用无人机的绘制方法
for (int j = 0; j < droneList.size(); j++) {
droneList.get(j).drawDrone(bg);
droneList.get(j).moveDrone();
}
// 遍历入侵者数组,调用入侵者的绘制方法
for (int j = 0; j < intruderList.size(); j++) {
intruderList.get(j).drawIntruder(bg);
intruderList.get(j).moveIntruder();
}
// 无人机扫描入侵者:每个无人机扫描自己周围区域
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++) {
int colorNum = image.getRGB(i, j);
Color color = new Color(colorNum);
// 灰度值小于10,认为是入侵者(黑色)
if ((color.getRed() + color.getGreen() + color.getBlue()) / 3 < 10) {
for (int l = 0; l < intruderList.size(); l++) {
Intruder intruder = intruderList.get(l);
if (i < intruder.x + intruder.size && i >= intruder.x
&& j >= intruder.y && j < intruder.y + intruder.size) {
drone.speedx = intruder.speedx;
drone.speedy = intruder.speedy;
break;
}
}
}
}
}
}
}
// 入侵者扫描无人机:每个活着的入侵者扫描周围区域,检测到无人机则扣血
for (int i = 0; i < intruderList.size(); i++) {
System.out.println("入侵者进入检测");
Intruder intruder = intruderList.get(i);
if (intruder.HP <= 0) {
continue;
}
for (int j = intruder.x - 15; j < intruder.x + 70; j++) {
boolean flag = false;
for (int k = intruder.y - 15; k < intruder.y + 70; k++) {
int colorNum = image.getRGB(j, k);
Color color = new Color(colorNum);
int gray = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
// 灰度值在30~150之间且红色分量<100,认为是无人机(紫色)
if (gray > 30 && gray < 150 && color.getRed() < 100) {
intruder.HP -= 1;
System.out.println("入侵者被检测到~" + intruder.HP);
flag = true;
break;
}
}
if (flag) {
break;
}
}
}
g.drawImage(image, 0, 0, null);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
无人机扫描(改进后):
遍历所有无人机(
for (int k = 0; k < droneList.size(); k++)),实现多机同时扫描。扫描区域:从
drone.x到drone.x+scanSize,drone.y到drone.y+scanSize。遍历区域内每个像素,计算灰度值,若小于10(接近黑色),则认为是入侵者的黑色像素。
进一步通过坐标判断该像素是否落在某个入侵者的矩形内(入侵者绘制为黑色圆形,但检测时用矩形包围盒),若匹配,则将该无人机的速度设置为该入侵者的速度,实现"跟随"。
入侵者扫描(改进后):
遍历每个活着的入侵者(
HP>0)。扫描范围:从
intruder.x-15到intruder.x+70,intruder.y-15到intruder.y+70(约比自身大一圈)。遍历像素,计算灰度值,若满足
gray>30 && gray<150 && color.getRed()<100,则认为检测到无人机(紫色机体RGB约(94,20,223),灰度约112,红色分量小),入侵者HP减1。一旦检测到,立即跳出循环(避免同一帧多次扣血)。
项目更新涉及知识点
1.入侵者存储与攻击机制
1.1 入侵者的存储方式
入侵者对象的集合在 DroneUI 中初始化:
ArrayList<Intruder> intruderList = new ArrayList<>();
随后通过引用传递注入到 DroneThread:
dt.intruderList = intruderList;
在 DroneThread 中,使用成员变量持有该引用:
ArrayList<Intruder> intruderList;
存储特点:
-
使用
ArrayList作为容器,支持动态增删。 -
该列表被两个线程共享:
DroneThread(读取/修改入侵者 HP)和DroneListener(添加新入侵者)。由于未加同步锁,存在并发修改风险。 -
每个
Intruder对象包含坐标、速度、大小、HP 等属性,其中HP是攻击机制的核心指标。
1.2 无人机扫描入侵者:发现与追踪
1.2.1 扫描循环结构
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++) {
// 像素检测...
}
}
}
}
-
外层循环:遍历所有无人机。
-
内层双重循环 :遍历当前无人机扫描区域内的每个像素(
scanSize = 100,即 100×100 像素区域)。
1.2.2 像素级判定逻辑
int colorNum = image.getRGB(i, j);
Color color = new Color(colorNum);
if ((color.getRed() + color.getGreen() + color.getBlue()) / 3 < 10) {
// 认为是入侵者(黑色)
for (int l = 0; l < intruderList.size(); l++) {
Intruder intruder = intruderList.get(l);
if (i < intruder.x + intruder.size && i >= intruder.x
&& j >= intruder.y && j < intruder.y + intruder.size) {
drone.speedx = intruder.speedx;
drone.speedy = intruder.speedy;
break;
}
}
}
判定依据:
-
入侵者绘制为纯黑色(
Color.BLACK),其 RGB 均为 0,灰度值 = 0。代码取阈值< 10。 -
一旦发现黑色像素,再通过坐标范围判断该像素是否落在某个入侵者的矩形包围盒 内(
intruder.x到intruder.x+size,y同理)。
攻击效果:
- 将无人机的速度设置为入侵者的速度,从而实现"跟随"。这并非直接扣血,而是模拟锁定并追踪目标。
1.3 无人机扫描入侵者:扣血攻击
1.3.1 扫描循环结构
for (int i = 0; i < intruderList.size(); i++) {
Intruder intruder = intruderList.get(i);
if (intruder.HP <= 0) {
continue;
}
for (int j = intruder.x - 15; j < intruder.x + 70; j++) {
boolean flag = false;
for (int k = intruder.y - 15; k < intruder.y + 70; k++) {
// 像素检测...
}
if (flag) break;
}
}
-
外层循环:遍历所有入侵者。
-
健康检查 :跳过已死亡(
HP <= 0)的入侵者。 -
扫描区域 :从
x-15到x+70,y-15到y+70。入侵者自身大小为 45,该区域比自身略大(左右各扩大约 15 像素),用于检测靠近的无人机。
1.3.2 像素级判定逻辑
int colorNum = image.getRGB(j, k);
Color color = new Color(colorNum);
int gray = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
if (gray > 30 && gray < 150 && color.getRed() < 100) {
intruder.HP -= 1;
System.out.println("入侵者被检测到~" + intruder.HP);
flag = true;
break;
}
判定依据:
-
无人机机体颜色为紫色
(94,20,223),计算其灰度 ≈ (94+20+223)/3 ≈ 112,红色分量 94 < 100。 -
因此阈值设为
gray > 30 && gray < 150 && color.getRed() < 100,能够匹配紫色区域,同时排除背景白色(灰度 255)和红色边框(红色分量 255)。
攻击效果:
-
入侵者每被检测到一次,
HP减 1。 -
HP初始为 100,归零后不再绘制和移动,视为被摧毁。
项目运行展示
项目开发阻碍
1.程序运行一段时间后崩溃,报数组越界异常
现象 :程序运行几分钟,或频繁点击生成按钮后直接崩溃,控制台报ArrayIndexOutOfBoundsException。

根本原因:
- 多线程并发修改集合:EDT 线程(监听器)往
ArrayList里 add 对象,子线程在遍历ArrayList,导致并发修改异常或数组越界 - 调用
image.getRGB(i,j)时,i 或 j 超出了BufferedImage的 1200x950 范围,导致数组越界 - 用 fori 循环遍历集合时,集合中的元素被移除,导致索引超出集合当前长度
解决方案:
修改扫描区域、图像边界、无人机移动范围、入侵者移动范围,通过画图计算,不让扫描区域超出图像边界。
(AI提供解决方案:
- 对集合的操作加锁,或使用线程安全的集合
CopyOnWriteArrayList,避免并发修改问题- 调用
getRGB()前,先判断 i 和 j 是否在图片尺寸范围内,超出则直接跳过- 遍历集合时使用迭代器
Iterator,或倒序遍历,避免增删元素导致的索引越界)
后续改进方向
1.完善智能对抗策略
- 实现需求文档中定义的定点清除 和移动目标拦截两种对抗模式,针对固定目标和移动目标采用不同的追踪策略
- 加入移动目标位置预测,根据入侵者的当前速度和位置,预测下一帧的坐标,提前进行拦截,而非单纯的速度同步
- 实现广播机制 与任务分配机制,让所有无人机共享入侵者信息,每个无人机同一时间只锁定一个目标,避免资源浪费,实现多无人机协同围剿
- 加入无人机优先级策略,优先拦截距离防守区最近的入侵者,提升防御效果
2.性能与检测逻辑优化
- 优化扫描检测逻辑,采用矩形粗筛 + 像素精检的方式,先判断边界是否相交,再执行像素检测,大大减少循环次数,降低 CPU 占用
- 优化颜色识别逻辑,采用特定颜色通道区分目标,提升检测准确率,避免背景干扰
- 优化双缓冲逻辑,复用
BufferedImage对象,避免每一帧都创建新的对象,减少 GC 压力
3.玩法与 UI 交互扩展
- 加入可视化的血量条、得分系统、击杀数统计,提升交互体验
- 加入难度等级系统,随着游戏时间增加,入侵者的数量、速度、血量逐步提升,增加游戏挑战性
- 加入暂停、继续、重置游戏、调整难度的按钮,完善游戏的基础功能
- 给无人机和入侵者加入等级系统,不同等级的无人机有不同的扫描范围、移动速度、攻击力
- 加入音效系统,扫描到目标、击杀入侵者时播放对应音效,提升游戏沉浸感

