一、项目概述
本项目基于Java Swing实现了一个可视化的智能无人机平台,核心功能包括无人机巡逻、入侵者生成、无人机扫描追踪入侵者、入侵者血量扣减及状态可视化等。整体架构分为5个核心类,各司其职且协同工作,实现了多线程下的图形动态渲染和逻辑交互。
二、核心类解析
1. Drone类(无人机核心实体类)
该类封装了无人机的属性和行为,核心是无人机的绘制(含状态可视化)、移动逻辑,以及状态控制方法。
java
package duoxiancheng.xq0127.dronev3;
import java.awt.*;
public class Drone {
int x,y; // 无人机坐标
int speedx,speedy; // 无人机x/y轴移动速度
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; // 初始化状态(默认0=巡逻)
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是透明度,0-255)
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;
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);
}
// 无人机移动逻辑:边界碰撞检测+位置修正
public void move() {
// 1. 标记是否碰到x/y轴边界
boolean hitX = false;
boolean hitY = false;
// x轴边界:左200,右1000(扫描圈右边界)
if (x < 200 || (x + scanSize) > 1000) {
speedx = -speedx; // 碰到边界反转x轴速度
hitX = true;
}
// y轴边界:上175,下775(扫描圈下边界)
if (y < 175 || (y + scanSize) > 775) {
speedy = -speedy; // 碰到边界反转y轴速度
hitY = true;
}
// 2. 边界位置修正:避免无人机卡墙
if (hitX) {
x = Math.max(200, Math.min(1000 - scanSize, x));
}
if (hitY) {
y = Math.max(175, Math.min(775 - scanSize, y));
}
// 3. 执行移动
x += speedx;
y += speedy;
}
// 状态设置方法:供外部修改无人机状态(核心接口)
public void setState(int state) {
this.state = state;
}
// 状态获取方法:供外部读取无人机状态,暂时未使用
public int getState() {
return this.state;
}
}
关键点:
- 状态可视化:通过
switch语句将state值映射为不同颜色,实现"巡逻黄、攻击红、补充弹药灰"的视觉效果; - 边界碰撞:移动逻辑中先判断边界再修正位置,避免无人机卡在边界无法移动;
- 状态控制接口:
setState/getState方法实现了无人机状态的外部可控,是状态动态切换的核心。
2. DroneListener类(事件监听类)
该类实现按钮点击事件监听,负责随机生成无人机和入侵者,控制生成位置、速度的合法性。
java
package duoxiancheng.xq0127.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<Drone> droneList; // 无人机列表(关联UI层的列表)
ArrayList<Intruder> intruderList; // 入侵者列表(关联UI层的列表)
Random random = new Random(); // 随机数生成器
@Override
public void actionPerformed(ActionEvent e) {
String ac = e.getActionCommand(); // 获取按钮点击指令
if(ac.equals("生产无人机")){
// 1. 随机生成无人机初始坐标(限定在200-900 x 175-675范围内)
int x = 200+random.nextInt(700);
int y = 175+random.nextInt(500);
// 2. 随机生成移动速度(-2到2之间,避免速度为0)
int speedx = random.nextInt(5)-2;
int speedy = random.nextInt(5)-2;
// 循环确保速度不为0(避免无人机静止)
while (true){
if(speedx != 0 || speedy != 0){
break;
}
speedx = random.nextInt(5)-2;
speedy = random.nextInt(5)-2;
}
// 3. 创建无人机(默认状态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. 确保入侵者生成在指定区域外(200-1000 x 175-775区域外)
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. 随机生成入侵者速度(避免速度为0)
int speedx = random.nextInt(5)-2;
int speedy = random.nextInt(5)-2;
while (true) {
if (speedx != 0 || speedy != 0) {
break;
}
speedx = random.nextInt(5) - 2;
speedy = random.nextInt(5) - 2;
}
// 4. 创建入侵者并加入列表
Intruder itd = new Intruder(x,y,speedx,speedy,intruderSize);
intruderList.add(itd);
}
}
}
关键点:
- 速度合法性:通过
while循环确保无人机/入侵者速度不为0,避免实体静止; - 位置合法性:入侵者生成时限定在指定区域外,保证初始位置符合业务逻辑;
- 事件解耦:通过监听按钮指令生成实体,将"UI操作"和"实体创建"解耦。
3. DroneThread类(核心业务线程类)
该类是后台线程,负责循环执行无人机/入侵者的绘制、移动、扫描、碰撞检测等核心逻辑,是整个程序的"驱动核心"。
【该类最重要也最复杂】
java
package duoxiancheng.xq0127.dronev3;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
public class DroneThread extends Thread{
ArrayList<Drone> droneList; // 无人机列表(关联UI层)
ArrayList<Intruder> intruderList; // 入侵者列表(关联UI层)
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 < intruderList.size(); i++) {
Intruder intruder = intruderList.get(i);
intruder.drawIntruder(bg); // 绘制入侵者
intruder.move(); // 移动入侵者
}
// 5. 无人机扫描入侵者逻辑(核心业务)
if(droneList.size()>0){
for (int k = 0; k < droneList.size(); k++) {
Drone drone = droneList.get(k);
boolean foundIntruder = false; // 标记是否检测到存活入侵者
// 遍历无人机雷达扫描范围内的每个像素
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){
foundIntruder = true; // 标记检测到入侵者
// 计算无人机到入侵者的方向向量
int dx = itr.x - drone.x;
int dy = itr.y - drone.y;
double distance = Math.sqrt(dx*dx + dy*dy);
if (distance > 0) {
// 归一化方向向量,设置无人机向入侵者移动
drone.speedx = (int) (dx / distance * 3);
drone.speedy = (int) (dy / distance * 3);
drone.setState(1); // 切换为攻击状态
}
break;
}
}
}
}
}
}
// 未检测到入侵者时,恢复巡逻状态
if(!foundIntruder){
drone.setState(0);
}
}
}
// 6. 入侵者血量扣减逻辑
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<150 && gray>30 && c.getRed()<100){
flag = true;
break;
}
}
if(flag){
break;
}
}
// 被扫描到则扣减血量
if(flag && intruder.blood > 0){
intruder.blood--;
}
}
// 7. 无人机碰撞检测:避免无人机重叠
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) {
// 轻微推开,避免重叠
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));
}
}
}
}
// 8. 将缓冲图片渲染到窗口
g.drawImage(img,0,0,null);
// 线程休眠1ms:控制帧率,避免CPU占用过高
try {
Thread.sleep(1);
}catch (InterruptedException e){
throw new RuntimeException(e);
}
}
}
}
关键点:
- 双缓冲技术:通过
BufferedImage绘制后再渲染到窗口,解决Swing绘图闪烁问题; - 扫描逻辑:通过像素颜色检测入侵者,实现"视觉扫描"效果,符合无人机雷达的业务逻辑;
- 状态自动切换:通过
foundIntruder标记实现"检测到入侵者→攻击态,未检测到→巡逻态"的自动切换; - 碰撞检测:无人机间距离过近时轻微推开,避免视觉重叠,提升交互体验;
- 帧率控制:
Thread.sleep(1)控制循环频率,平衡渲染流畅度和CPU占用。
4. DroneUI类(UI界面类)
该类是程序入口,负责创建窗口、按钮、关联列表和线程,是整个程序的"容器"。
java
package duoxiancheng.xq0127.dronev3;
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); // 窗口大小
setDefaultCloseOperation(EXIT_ON_CLOSE); // 关闭窗口退出程序
setLocationRelativeTo(null); // 窗口居中
// 2. 创建按钮面板(底部)
JPanel btnPanel = new JPanel();
btnPanel.setBackground(Color.LIGHT_GRAY); // 面板背景色
// 3. 创建功能按钮
JButton createDroneBtn = new JButton("生产无人机");
btnPanel.add(createDroneBtn);
JButton createIntryderBtn = new JButton("生产入侵者");
btnPanel.add(createIntryderBtn);
// 4. 布局管理:按钮面板放在窗口底部
add(btnPanel,BorderLayout.SOUTH);
setVisible(true); // 显示窗口
Graphics g = this.getGraphics(); // 获取窗口绘图上下文
// 5. 初始化线程和监听器
DroneThread dt = new DroneThread(g); // 后台业务线程
DroneListener droneL = new DroneListener(); // 按钮监听器
// 6. 绑定按钮事件
createDroneBtn.addActionListener(droneL);
createIntryderBtn.addActionListener(droneL);
// 7. 共享列表:将UI层的列表传递给监听器和线程(核心:数据共享)
droneL.droneList = droneList;
dt.droneList = droneList;
droneL.intruderList = intruderList;
dt.intruderList = intruderList;
// 8. 启动后台线程
dt.start();
}
// 重写paint方法:保留父类逻辑,确保绘图正常
public void paint(Graphics g){
super.paint(g);
}
// 程序入口
public static void main(String[] args){
new DroneUI();
}
}
关键点:
- 数据共享:通过将
droneList/intruderList传递给监听器和线程,实现UI层、监听层、业务层的数据统一; - 布局管理:使用
BorderLayout将按钮面板放在底部,符合桌面应用的交互习惯; - 线程启动:在UI初始化完成后启动后台线程,避免UI阻塞。
5. Intruder类(入侵者实体类)
该类封装了入侵者的属性和行为,核心是入侵者绘制(含血量条可视化)、移动逻辑。
java
package duoxiancheng.xq0127.dronev3;
import java.awt.*;
public class Intruder {
int x,y; // 入侵者坐标
int speedx,speedy; // 入侵者移动速度
int size; // 入侵者大小
int blood; // 入侵者血量(初始100)
// 构造方法:初始化入侵者属性
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); // 黑色填充圆
g.setColor(Color.RED);
g.drawOval(x-1,y-1,size+2,size+2); // 红色边框
// 2. 绘制血量条背景(红色)
g.setColor(Color.RED);
g.fillRect(x,y+size+5,size,6); // 位置:入侵者下方5像素,宽度=入侵者大小,高度6
// 3. 绘制剩余血量(绿色,按比例显示)
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){ // 血量为0时不移动
return;
}
// x轴边界:左5,右1200-5
if(x < 5 || (x+size+5) > 1200){
speedx = -speedx; // 反转x轴速度
}
// y轴边界:上25,下950-5
if(y < 25 || (y+size+5) > 950){
speedy = -speedy; // 反转y轴速度
}
// 执行移动
x += speedx;
y += speedy;
}
}
关键点:
- 血量可视化:通过"红色背景+绿色比例条"实现血量条,
bloodWidth按血量百分比计算,直观展示剩余血量; - 边界逻辑:移动时判断边界并反转速度,实现入侵者的"反弹"效果;
- 存活判断:血量≤0时不绘制、不移动,实现"死亡"的视觉和逻辑效果。
三、核心技术总结
- 多线程:通过
DroneThread实现后台业务逻辑与UI线程分离,避免UI阻塞; - 双缓冲绘图:解决Swing动态绘图的闪烁问题,提升视觉体验;
- 状态可视化:通过颜色映射实现无人机状态、入侵者血量的直观展示;
- 碰撞检测:包含边界碰撞(无人机/入侵者)、实体碰撞(无人机间),保证交互合理性;
- 数据共享:通过全局列表实现多层级的数据统一,是多模块协同的核心。