V1.0
预期功能
将一个无人机模型呈现在窗体上,并能使其丝滑移动,触壁反弹
难点:轨迹消除,画面闪烁
代码实现
首先我们要创建一个DroneUI类,并继承JFrame窗口类,用于设定初始窗口样式
java
public class DroneUI extends JFrame {}
接下来在UI类中写DroneUI的构造方法,并在构造方法中调整窗口布局和样式
java
public DroneUI(){
this.setTitle("智能无人机指挥系统");
this.setSize(800,800);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);//窗体居中显示到屏幕正中间
this.setVisible(true);
}
我们知道,系统在一个进程当中一次仅能处理一件事,例如我先后写了两个循环,那么系统只会执行完第一个循环后再执行第二个循环
假如我现在需要同时进行两个循环,该如何去做呢?
在上一节中,我们学习了线程,这里便可以使用线程去实现(虽然目前用不到)
这里我们使用线程去实现图像绘制移动操作
首先创建DroneThread类,继承Thread类,并重写run方法,将需要完成的操作写入其中(这里需要绘制无人机图形并使其移动)
无人机图形方法如下
java
public void drawDrone(Graphics bg,int x,int y,int speedx,int speedy){
Color c = new Color(71, 255, 81, 60);
bg.setColor(c);
bg.fillOval(x,y,200,200);
Color c1 = new Color(25, 241, 36);
bg.setColor(c1);
bg.fillOval(x+80,y+80,40,40);
Color c2 = new Color(203, 39, 39);
bg.setColor(c2);
bg.fillOval(x+95,y+95,10,10);
}
我们知道,直接调用画笔去在面板上绘图会有一个绘画过程的动画,为了使图像显示更加丝滑,我们可以使用画布BufferedImage缓存,在画布上绘画后直接显示
java
//缓存技术(布是不动的,只是缓存画像最后显示)
BufferedImage img=new BufferedImage(800,800,2);
Graphics bg=img.getGraphics();
bg.setColor(Color.WHITE);
bg.fillRect(0,0,800,800);
drawDrone(bg,x,y,speedx,speedy);
drawDrone(bg,x1,y1,speedx1,speedy1);
g.drawImage(img,0,0,null);
(tips.这里白色背景板的填充操作需要在画布上进行,否则会出现图像闪烁问题)
记得要在画布刷白之前添加一个延时操作,否则所有图像的显示只是一瞬间,肉眼能够看到的画面只有最后绘制的图片(只需要打出Thread.sleep(),鼠标悬停点击自动补全即可)
java
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
接下来便是触底反弹的实现
当抵达边界时,我们让速度取反即可
java
if (x>600||x<0){
speedx=-speedx;
}
if (y>600||y<0){
speedy=-speedy;
}
x+=speedx;
y+=speedy;
if (x1>600||x1<0){
speedx1=-speedx1;
}
if (y1>600||y1<0){
speedy1=-speedy1;
}
x1+=speedx1;
y1+=speedy1;
完整代码
droneUI
java
package HolidayMainPackage.day0126.DroneV1;
import javax.swing.*;
import java.awt.*;
public class DroneUI extends JFrame {
public DroneUI(){
this.setTitle("智能无人机指挥系统");
this.setSize(800,800);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
DroneThread dt = new DroneThread(this.getGraphics());
dt.start();
}
//绘制刷新窗体,每改变一次窗体状态都会调用一次paint函数
@Override
public void paint(Graphics g) {
super.paint(g);
}
public static void main(String[] args) {
new DroneUI();
}
}
DroneThread
java
package HolidayMainPackage.day0126.DroneV1;
import java.awt.*;
import java.awt.image.BufferedImage;
public class DroneThread extends Thread{
Graphics g;
int x = 400, y = 300;
int x1=100,y1=100;
int speedx1=1,speedy1=1;
int speedx=2,speedy=2;
public DroneThread(Graphics g){
this.g = g;
}
@Override
public void run() {
for(int i = 0; ; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//缓存技术(布是不动的,只是缓存画像最后显示)
BufferedImage img=new BufferedImage(800,800,2);
Graphics bg=img.getGraphics();
bg.setColor(Color.WHITE);
bg.fillRect(0,0,800,800);
//解决多线程闪烁问题
drawDrone(bg,x,y,speedx,speedy);
drawDrone(bg,x1,y1,speedx1,speedy1);
g.drawImage(img,0,0,null);
if (x>600||x<0){
speedx=-speedx;
}
if (y>600||y<0){
speedy=-speedy;
}
x+=speedx;
y+=speedy;
if (x1>600||x1<0){
speedx1=-speedx1;
}
if (y1>600||y1<0){
speedy1=-speedy1;
}
x1+=speedx1;
y1+=speedy1;
}
}
public void drawDrone(Graphics bg,int x,int y,int speedx,int speedy){
Color c = new Color(71, 255, 81, 60);
bg.setColor(c);
bg.fillOval(x,y,200,200);
Color c1 = new Color(25, 241, 36);
bg.setColor(c1);
bg.fillOval(x+80,y+80,40,40);
Color c2 = new Color(203, 39, 39);
bg.setColor(c2);
bg.fillOval(x+95,y+95,10,10);
}
}
V2.0
预期功能
- 可通过按钮点击生成己方和敌方无人机
- 规定己方和敌方无人机生成范围及运动范围
难点:生成范围限制,点击生成操作
代码实现
前面我们已经初步编写了无人机的运行代码,对于多架无人机同时运动这一操作,我们采用的方法是逐个编写,一架两架可以这么写,但100架、1000架呢?
这时候有同学便会说:啊,那我一个一个写不也可以实现嘛
那如果我要求通过按钮来操控无人机的生成(生成数量不定),那该如何去写呢?
有同学可能想到用多线程去解决,按一次按钮加一个线程
但是我们要知道,系统的线程数量是有限的,所以这样做效率并不高
正确的做法是:++将无人机作为一个对象,包含各种属性方法,每次点击按钮,就创建一个对象存入数组,然后统一在单个线程内实现绘制++
这样做编写的操作便会简化很多
在了解了做法后,我们要知道无人机Drone类需要包含哪些属性和方法
大概包含内容如下
|-------------------|--------|
| 属性 | 方法 |
| 坐标(x,y) | 构造方法 |
| 速度(speedx,speedy) | 绘制方法 |
| 雷达范围 | 移动方法 |
| 尺寸 | 雷达扫描 |
| 状态 | 攻击方法 |
无人机类代码如下
java
public class Drone {
int x,y,speedx,speedy,size;
int state;
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;
size=40;
scanSize=200;
}
public void drawDrone(Graphics bg){
Color c = new Color(71, 255, 81, 60);
bg.setColor(c);
bg.fillOval(x,y,scanSize,scanSize);
Color c1 = new Color(25, 241, 36);
bg.setColor(c1);
bg.fillOval(x+80,y+80,size,size);
Color c2 = new Color(203, 39, 39);
bg.setColor(c2);
bg.fillOval(x+95,y+95,10,10);
}
public void move(){
if (x>840-size||x<200){
speedx=-speedx;
}
if (y>615-size||y<175){
speedy=-speedy;
}
x+=speedx;
y+=speedy;
}
}
敌机同理
java
public class Intruder {
int x,y,speedx,speedy,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;
blood=100;
}
public void drawIntruder(Graphics bg){
if (blood<=0){
return;
}
bg.setColor(Color.RED);
bg.fillOval(x-1,y-1,size+2,size+2);
bg.setColor(Color.BLACK);
bg.fillOval(x,y,size,size);
}
public void move(){
if (blood<=0){
return;
}
if (x>1200-size||x<0){
speedx=-speedx;
}
if (y>950-size||y<0){
speedy=-speedy;
}
x+=speedx;
y+=speedy;
}
}
添加按钮的操作这里就省略了(需要两个按钮,一个是"添加无人机",一个是"生产入侵者")
为了方便按钮的添加,可以在窗体底部添加一个Jpanel面板,用于安置按钮
同时在UI类中创建droneList和intList动态数组用于存储创建的单位,并将其地址传入监听类和线程类
java
ArrayList<Drone> droneList=new ArrayList<>();
ArrayList<Intruder> intList=new ArrayList<>();
//将共享内存空间的数组传入到两个线程当中
droneL.droneList = droneList;//监听器线程(监听器本身为一个线程,只不过不需要我们去编写的线程)
dt.droneList = droneList;//无人机线程
droneL.intList = intList;
dt.intList = intList;
当有按钮被点击时,我们便在监听类中生成相关属性、创建单位对象并存入数组
java
public void actionPerformed(ActionEvent e) {
String ac=e.getActionCommand();
if(ac.equals("添加无人机")){
int x = random.nextInt(500)+300;
int y = random.nextInt(300)+275;
int speedx = random.nextInt(5) -2;//-2~2
int speedy = random.nextInt(5) -2;
Drone drone = new Drone(x,y,0,speedx,speedy);
System.out.println(x+"||||"+y);
droneList.add(drone);}
else if(ac.equals("生产入侵者")){
int x,y;
while(true){
x = random.nextInt(1150);
y = random.nextInt(900);
if(x<200||x>1000||y<175||y>775){
break;
}
}
int speedx = random.nextInt(5) -2;//-2~2
int speedy = random.nextInt(5) -2;
Intruder intruder = new Intruder(x,y,speedx,speedy,45);
intList.add(intruder);
}
}
然后再在线程类中去调用方法读取数据绘制图形
(虽然线程类只运行一次,但其中的死循环总会读取到更新的状态)
java
//遍历无人机系统
for (int j=0;j<droneList.size();j++){
Drone drone=droneList.get(j);
drone.drawDrone(bg);
drone.move();
}
for (int j=0;j<intList.size();j++){
Intruder intruder=intList.get(j);
intruder.drawIntruder(bg);
intruder.move();
}
此外,我还添加了一个己方单位生成及运动区域,敌方单位只能在此矩形范围外生成,但运行范围是全窗口
矩形区域如下
java
bg.setColor(Color.RED);
bg.drawRect(200,175,800,600);
写到这里,细心的同学可能就要问了:哎主包,我记得你不是还添加了一个什么雷达范围嘛,这玩意咋没用上呢
别急,下面就来讲雷达作用
顾名思义,雷达就是用来探测敌方单位是否进入己方攻击范围的
那么如何去实现这一点呢
有两种方法,最容易想到的便是直接判断两坐标距离,但这样便需要时时刻刻把所有己方单位和敌方单位的坐标都判断一遍,未免有些太费力不讨好了
更简单的方法便是判断己方雷达范围内是否出现敌方单位颜色(灰度判断)
代码如下
java
//检测周围是否有颜色变化\
if(!droneList.isEmpty()) {
System.out.println("进入检测");
Drone drone = droneList.get(0);
for (int i = drone.x; i < drone.x+drone.scanSize; i++) {
for (int j = drone.y; j < drone.y+drone.scanSize; j++) {
int colorNum = img.getRGB(i, j);
Color c = new Color(colorNum);
if ((c.getRed() + c.getBlue() + c.getGreen()) / 3 < 10) {
System.out.println("雷达扫到了");
}
}
}
}
完整代码
Drone
java
package HolidayMainPackage.day0127.DroneV2;
import java.awt.*;
//将无人机视为一个对象,可简化操作
public class Drone {
int x,y,speedx,speedy,size;
int state;
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;
size=40;
scanSize=200;
}
public void drawDrone(Graphics bg){
Color c = new Color(71, 255, 81, 60);
bg.setColor(c);
bg.fillOval(x,y,scanSize,scanSize);
Color c1 = new Color(25, 241, 36);
bg.setColor(c1);
bg.fillOval(x+80,y+80,size,size);
Color c2 = new Color(203, 39, 39);
bg.setColor(c2);
bg.fillOval(x+95,y+95,10,10);
}
public void move(){
if (x>840-size||x<200){
speedx=-speedx;
}
if (y>615-size||y<175){
speedy=-speedy;
}
x+=speedx;
y+=speedy;
}
}
Intruder
java
package HolidayMainPackage.day0127.DroneV2;
import java.awt.*;
public class Intruder {
int x,y,speedx,speedy,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;
blood=100;
}
public void drawIntruder(Graphics bg){
if (blood<=0){
return;
}
bg.setColor(Color.RED);
bg.fillOval(x-1,y-1,size+2,size+2);
bg.setColor(Color.BLACK);
bg.fillOval(x,y,size,size);
}
public void move(){
if (blood<=0){
return;
}
if (x>1200-size||x<0){
speedx=-speedx;
}
if (y>950-size||y<0){
speedy=-speedy;
}
x+=speedx;
y+=speedy;
}
}
DroneUI
java
package HolidayMainPackage.day0127.DroneV2;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class DroneUI extends JFrame {
ArrayList<Drone> droneList=new ArrayList<>();
ArrayList<Intruder> intList=new ArrayList<>();
public DroneUI(){
this.setTitle("智能无人机指挥系统");
this.setSize(1200,1000);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
JPanel btnPanel = new JPanel();
btnPanel.setBackground(Color.LIGHT_GRAY);
JButton btn = new JButton("添加无人机");
btnPanel.add(btn) ;
JButton btn1 = new JButton("生产入侵者");
btnPanel.add(btn1);
add(btnPanel,BorderLayout.SOUTH);
this.setVisible(true);
//无人机线程
DroneThread dt = new DroneThread(this.getGraphics());
//监听器
DroneListener droneL = new DroneListener();
//按钮注册
btn.addActionListener(droneL);
btn1.addActionListener(droneL);
addMouseListener(droneL);
//将共享内存空间的数组传入到两个线程当中
droneL.droneList = droneList;//监听器线程(监听器本身为一个线程,只不过不需要我们去编写的线程)
dt.droneList = droneList;//无人机线程
droneL.intList = intList;
dt.intList = intList;
dt.start();
}
//绘制刷新窗体,每改变一次窗体状态都会调用一次paint函数
@Override
public void paint(Graphics g) {
super.paint(g);
}
public static void main(String[] args) {
new DroneUI();
}
}
DroneListener
java
package HolidayMainPackage.day0127.DroneV2;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Random;
public class DroneListener extends MouseAdapter implements ActionListener {
ArrayList<Drone> droneList;
ArrayList<Intruder> intList;
Random random = new Random();
@Override
public void actionPerformed(ActionEvent e) {
String ac=e.getActionCommand();
if(ac.equals("添加无人机")){
int x = random.nextInt(500)+300;
int y = random.nextInt(300)+275;
int speedx = random.nextInt(5) -2;//-2~2
int speedy = random.nextInt(5) -2;
Drone drone = new Drone(x,y,0,speedx,speedy);
System.out.println(x+"||||"+y);
droneList.add(drone);}
else if(ac.equals("生产入侵者")){
int x,y;
while(true){
x = random.nextInt(1150);
y = random.nextInt(900);
if(x<200||x>1000||y<175||y>775){
break;
}
}
int speedx = random.nextInt(5) -2;//-2~2
int speedy = random.nextInt(5) -2;
Intruder intruder = new Intruder(x,y,speedx,speedy,45);
intList.add(intruder);
}
}
@Override
public void mouseClicked(MouseEvent e) {
int x,y;
x= e.getX();
y= e.getY();
System.out.println("x是"+x+"y是"+y);
}
}
DroneThread
java
package HolidayMainPackage.day0127.DroneV2;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
public class DroneThread extends Thread{
Graphics g;
ArrayList<Drone> droneList;
ArrayList<Intruder> intList;
public DroneThread(Graphics g){
this.g = g;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//缓存技术(布时不动的,只是缓存画像最后显示)
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);
//遍历无人机系统
for (int j=0;j<droneList.size();j++){
Drone drone=droneList.get(j);
drone.drawDrone(bg);
drone.move();
}
for (int j=0;j<intList.size();j++){
Intruder intruder=intList.get(j);
intruder.drawIntruder(bg);
intruder.move();
}
//检测周围是否有颜色变化\
if(!droneList.isEmpty()) {
System.out.println("进入检测");
Drone drone = droneList.get(0);
for (int i = drone.x; i < drone.x+drone.scanSize; i++) {
for (int j = drone.y; j < drone.y+drone.scanSize; j++) {
int colorNum = img.getRGB(i, j);
Color c = new Color(colorNum);
if ((c.getRed() + c.getBlue() + c.getGreen()) / 3 < 10) {
System.out.println("雷达扫到了");
}
}
}
}
g.drawImage(img,0,0,null);
}
}
}
V3.0
预期功能
添加新功能的同时微调了一些参数
- 敌方进入己方单位雷达范围扣血
- 敌方单位血条显示
- 己方单位扫描到敌方单位时会锁定一个单位并追踪
难点:
代码实现
敌方单位进入己方探测范围内时,感应自身所处区域是否出现颜色变化,颜色变化则扣血,血量归零时,自身所有函数return不执行
java
for (int j=0;j<intList.size();j++){
//System.out.println("入侵者进入检测");
Intruder intruder=intList.get(j);
if(intruder.blood<=0){
continue;
}
for (int i = intruder.x; i < intruder.x+intruder.size; i++) {
boolean flag=false;
for (int k = intruder.y; k < intruder.y+intruder.size; k++) {
int colorNum = img.getRGB(i, k);
Color c = new Color(colorNum);
if (c.getBlue()>0&&c.getGreen()>0&&c.getRed()<255) {
//System.out.println("入侵者被雷达扫到了");
intruder.blood-=1;
flag=true;
break;
}
}
if(flag){
break;
}
}
}
当无人机探测到敌方单位时,我们可以使其的速度更改为和敌方单位一致以达到追踪效果
(但难点是获取敌方单位速度,这里暂时将速度当成已知量处理)
java
//通过比对找到入侵对象(暂时取巧(作弊:天眼))
for (int l=0;l<intList.size();l++){
Intruder intruder=intList.get(l);
if(i<intruder.x+intruder.size&&i>=intruder.x&&j<intruder.y+intruder.size&&j<intruder.y+intruder.size&&j>=intruder.y&&(drone.x<840-drone.size&&drone.x>200&&drone.y<615-drone.size&&drone.y>175)){
drone.speedx=intruder.speedx;
drone.speedy=intruder.speedy;
break;
}
}
为了优化界面,我们可以给无人机添加一个状态显示(中心色圈),当显示黄色时代表有追踪任务,红色代表空闲
java
if(state==0) {
c2 = new Color(255, 0, 0);
}else{
c2 = new Color(255, 255, 0);
}
当无人机空闲时,恢复其原有速度,追踪时速度变为敌方单位速度
java
if (state==0){
runSpeedx=speedx;
runSpeedy=speedy;
}
雷达探测部分增加状态判断和更改
java
for (int k=0;k<droneList.size();k++){
boolean flag=false;
//System.out.println("进入检测");
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 = img.getRGB(i, j);
Color c = new Color(colorNum);
if ((c.getRed() + c.getBlue() + c.getGreen()) / 3 < 10) {
if(drone.state==0) {
//System.out.println("雷达扫到了");
//通过比对找到入侵对象(暂时取巧(作弊:天眼))
for (int l = 0; l < intList.size(); l++) {
Intruder intruder = intList.get(l);
if (i < intruder.x + intruder.size && i >= intruder.x && j < intruder.y + intruder.size && j < intruder.y + intruder.size && j >= intruder.y && (drone.x < 840 - drone.size && drone.x > 200 && drone.y < 615 - drone.size && drone.y > 175)) {
drone.runSpeedx = intruder.speedx;
drone.runSpeedy = intruder.speedy;
break;
}
}
}
//通知其他单位 广播
//自己可以跟随敌方单位
flag = true;
break;
}
}
if(flag){
drone.state=1;
break;
}
}
if(!flag){
drone.state=0;
}
}
当敌方单位被扫描到时增加血条显示
java
bg.setColor(Color.BLACK);
bg.drawRect(intruder.x+1,intruder.y-22,20,10);
bg.setColor(Color.GREEN);
bg.fillRect(intruder.x+2,intruder.y-21,(int)(intruder.blood/100.0*20),8);
bg.setColor(Color.RED);
bg.drawString(""+intruder.blood,intruder.x,intruder.y);
V4.0
预期功能
- 鼠标点击指派附近无人机前往
代码实现
这里我们单独创建一个Task去存属性,再创建一个TaskProThread类用于处理任务
思路大体如下
无人机总共三个状态,状态为零时为空闲,为一时为锁定敌方单位,为二时被指派任务
将任务存入taskList数组中,在线程中遍历,并遍历无人机数组以寻找距离指派点最近的无人机,然后更改其速度
代码如下
java
public void run(){
while(true) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
for (int i = 0; i < taskList.size(); i++) {
Task task = taskList.get(i);
if (task.getState() == 0) {
int min = 10000;
int index = 0;
for (int j = 0; j < droneList.size(); j++) {
Drone drone = droneList.get(j);
if (drone.state == 2 || drone.state == 1) {
continue;
}
int dis = (int) Math.sqrt((drone.x - task.getX()) * (drone.x - task.getX()) + (drone.y - task.getY()) * (drone.y - task.getY()));
if (min == 0 || dis < min) {
min = dis;
index = j;
}
}
Drone drone = droneList.get(index);
drone.tindex=i;
int dx = drone.x - task.x;
int dy = drone.y - task.y;
double dsx = Math.abs(drone.speedx);
double dn = Math.abs(dx + 0.0 / dsx);//宽度/速度
double dsy = (dy / dn);
dsx = drone.x < task.x ? dsx : -dsx;
drone.runSpeedx = dsx;
drone.runSpeedy = -dsy;
drone.state = 2;
task.state = 1;
}
}
if(!taskList.isEmpty()) {
for (int i = 0; i < droneList.size(); i++) {
Drone drone = droneList.get(i);
if (drone.state == 2) {
Task task = taskList.get(drone.tindex);
if (drone.x < task.x + 80 && drone.x >= task.x || drone.y < task.y + 80 && drone.y >= task.y) {
drone.runSpeedx = 0;
drone.runSpeedy = 0;
task.blood--;
}
if (task.blood <= 0) {
drone.tindex=0;
drone.state = 0;
}
}
}
}
}
}
完整代码
Drone
java
package HolidayMainPackage.day0127.DroneV4;
import java.awt.*;
//将无人机视为一个对象,可简化操作
public class Drone {
int x,y,speedx,speedy,size;
int tindex;
double runSpeedx,runSpeedy;
int state;
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;
size=40;
scanSize=200;
}
public void drawDrone(Graphics bg){
Color c = new Color(71, 255, 81, 60);
bg.setColor(c);
bg.fillOval(x,y,scanSize,scanSize);
Color c1 = new Color(25, 241, 36);
bg.setColor(c1);
bg.fillOval(x+80,y+80,size,size);
Color c2;
if(state==0) {
c2 = new Color(255, 0, 0);
}else{
c2 = new Color(255, 255, 0);
}
bg.setColor(c2);
bg.fillOval(x+95,y+95,10,10);
}
public void move(){
if (state==0){
runSpeedx=speedx;
runSpeedy=speedy;
}
if (x>835-size||x<205){
runSpeedx=-runSpeedx;
speedx=-speedx;
}
if (y>615-size||y<175){
runSpeedy=-runSpeedy;
speedy=-speedy;
}
x+=runSpeedx;
y+=runSpeedy;
}
}
DroneListener
java
package HolidayMainPackage.day0127.DroneV4;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Random;
public class DroneListener extends MouseAdapter implements ActionListener {
ArrayList<Drone> droneList;
ArrayList<Intruder> intList;
ArrayList<Task> taskList;
Random random = new Random();
@Override
public void actionPerformed(ActionEvent e) {
String ac=e.getActionCommand();
if(ac.equals("添加无人机")){
int x = random.nextInt(500)+300;
int y = random.nextInt(295)+275;
int speedx=0,speedy=0;
while(speedx==0||speedy==0) {
speedx = random.nextInt(5) - 2;//-2~2
speedy = random.nextInt(5) - 2;
}
Drone drone = new Drone(x,y,0,speedx,speedy);
System.out.println(x+"||||"+y);
droneList.add(drone);}
else if(ac.equals("生产入侵者")){
int x,y;
while(true){
x = random.nextInt(1050)+50;
y = random.nextInt(875)+15;
if(x<200||x>1000||y<175||y>775){
break;
}
}
int speedx=0,speedy=0;
while(speedx==0||speedy==0) {
speedx = random.nextInt(7) - 3;//-2~2
speedy = random.nextInt(7) - 3;
}
Intruder intruder = new Intruder(x,y,speedx,speedy,45);
intList.add(intruder);
}
}
@Override
public void mousePressed(MouseEvent e) {
int x,y;
x= e.getX();
y= e.getY();
if(x>910){
x=910;
} else if (x<205) {
x=205;
}
if (y>690){
y=690;
} else if (y<180) {
y=180;
}
Task task = new Task(x,y,0);
taskList.add(task);
//System.out.println("x是"+x+"y是"+y);
}
}
DroneThread
java
package HolidayMainPackage.day0127.DroneV4;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
public class DroneThread extends Thread{
Graphics g;
ArrayList<Drone> droneList;
ArrayList<Intruder> intList;
ArrayList<Task> taskList;
//被发现锁定的敌法单位数据(直到离开巡逻范围后清除)
public DroneThread(Graphics g){
this.g = g;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//缓存技术(布时不动的,只是缓存画像最后显示)
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);
//遍历无人机系统
for (int j=0;j<droneList.size();j++){
Drone drone=droneList.get(j);
drone.drawDrone(bg);
drone.move();
}
for (int j=0;j<taskList.size();j++){
Task task=taskList.get(j);
task.draw(bg);
}
for (int j=0;j<intList.size();j++){
Intruder intruder=intList.get(j);
intruder.drawIntruder(bg);
intruder.move();
}
//检测周围是否有颜色变化\
if(!droneList.isEmpty()) {
for (int k=0;k<droneList.size();k++){
boolean flag=false;
//System.out.println("进入检测");
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 = img.getRGB(i, j);
Color c = new Color(colorNum);
if ((c.getRed() + c.getBlue() + c.getGreen()) / 3 < 10) {
if(drone.state==0) {
//System.out.println("雷达扫到了");
//通过比对找到入侵对象(暂时取巧(作弊:天眼))
for (int l = 0; l < intList.size(); l++) {
Intruder intruder = intList.get(l);
if (i < intruder.x + intruder.size && i >= intruder.x && j < intruder.y + intruder.size && j < intruder.y + intruder.size && j >= intruder.y && (drone.x < 840 - drone.size && drone.x > 200 && drone.y < 615 - drone.size && drone.y > 175)) {
drone.runSpeedx = intruder.speedx;
drone.runSpeedy = intruder.speedy;
break;
}
}
}
//通知其他单位 广播
//自己可以跟随敌方单位
flag = true;
break;
}
}
if(flag&&drone.state!=2){
drone.state=1;
break;
}
}
if(!flag&&drone.state!=2){
drone.state=0;
}
}
for (int j=0;j<intList.size();j++){
//System.out.println("入侵者进入检测");
Intruder intruder=intList.get(j);
if(intruder.blood<=0){
continue;
}
for (int i = intruder.x; i < intruder.x+intruder.size; i++) {
boolean flag=false;
for (int k = intruder.y; k < intruder.y+intruder.size; k++) {
int colorNum = img.getRGB(i, k);
Color c = new Color(colorNum);
if (c.getBlue()>0&&c.getGreen()>0&&c.getRed()<255) {
//System.out.println("入侵者被雷达扫到了");
intruder.blood-=1;
bg.setColor(Color.BLACK);
bg.drawRect(intruder.x+1,intruder.y-22,20,10);
bg.setColor(Color.GREEN);
bg.fillRect(intruder.x+2,intruder.y-21,(int)(intruder.blood/100.0*20),8);
bg.setColor(Color.RED);
bg.drawString(""+intruder.blood,intruder.x,intruder.y);
flag=true;
break;
}
}
if(flag){
break;
}
}
}
}
g.drawImage(img,0,0,null);
}
}
}
DroneUI
java
package HolidayMainPackage.day0127.DroneV4;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class DroneUI extends JFrame {
ArrayList<Drone> droneList=new ArrayList<>();
ArrayList<Intruder> intList=new ArrayList<>();
ArrayList<Task> taskList=new ArrayList<>();
public DroneUI(){
this.setTitle("智能无人机指挥系统");
this.setSize(1200,1000);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
JPanel btnPanel = new JPanel();
btnPanel.setBackground(Color.LIGHT_GRAY);
JButton btn = new JButton("添加无人机");
btnPanel.add(btn) ;
JButton btn1 = new JButton("生产入侵者");
btnPanel.add(btn1);
add(btnPanel,BorderLayout.SOUTH);
this.setVisible(true);
//无人机线程
DroneThread dt = new DroneThread(this.getGraphics());
//监听器
DroneListener droneL = new DroneListener();
//按钮注册
btn.addActionListener(droneL);
btn1.addActionListener(droneL);
addMouseListener(droneL);
//将共享内存空间的数组传入到两个线程当中
droneL.droneList = droneList;//监听器线程(监听器本身为一个线程,只不过不需要我们去编写的线程)
dt.droneList = droneList;//无人机线程
droneL.intList = intList;
dt.intList = intList;
droneL.taskList = taskList;
dt.taskList = taskList;
dt.start();
TaskProThread t = new TaskProThread();
t.taskList = taskList;
t.droneList = droneList;
t.start();
}
//绘制刷新窗体,每改变一次窗体状态都会调用一次paint函数
@Override
public void paint(Graphics g) {
super.paint(g);
//Graphics图形工具类
// int x = 400, y = 300;
// Color c = new Color(71, 255, 81, 60);
// g.setColor(c);
// g.fillOval(x,y,200,200);
// Color c1 = new Color(25, 241, 36);
// g.setColor(c1);
// g.fillOval(x+80,y+80,40,40);
// Color c2 = new Color(203, 39, 39);
// g.setColor(c2);
// g.fillOval(x+95,y+95,10,10);
}
public static void main(String[] args) {
new DroneUI();
}
}
Intruder
java
package HolidayMainPackage.day0127.DroneV4;
import java.awt.*;
public class Intruder {
int x,y,speedx,speedy,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;
blood=100;
}
public void drawIntruder(Graphics bg){
if (blood<=0){
return;
}
bg.setColor(Color.RED);
bg.fillOval(x-1,y-1,size+2,size+2);
bg.setColor(Color.BLACK);
bg.fillOval(x,y,size,size);
}
public void move(){
if (blood<=0){
return;
}
if (x>1150-size||x<10){
speedx=-speedx;
}
if (y>940-size||y<15){
speedy=-speedy;
}
x+=speedx;
y+=speedy;
}
}
Task
java
package HolidayMainPackage.day0127.DroneV4;
import java.awt.*;
public class Task {
int x;
int y;
int blood;
int state;//0未被分配任务 1被分配 2已完成
public Task(int x, int y, int state) {
this.x = x;
this.y = y;
this.state = state;
blood=10;
}
public void draw(Graphics g){
if (blood<=0){
state=2;
return;
}
g.setColor(Color.BLACK);
g.fillRect(x,y,80,80);
}
public void setState(int state) {
this.state = state;
}
public int getState() {
return state;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
}
TaskProThread
java
package HolidayMainPackage.day0127.DroneV4;
import java.util.ArrayList;
public class TaskProThread extends Thread{
ArrayList<Task> taskList;
ArrayList<Drone> droneList;
public void run(){
while(true) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
for (int i = 0; i < taskList.size(); i++) {
Task task = taskList.get(i);
if (task.getState() == 0) {
int min = 10000;
int index = 0;
for (int j = 0; j < droneList.size(); j++) {
Drone drone = droneList.get(j);
if (drone.state == 2 || drone.state == 1) {
continue;
}
int dis = (int) Math.sqrt((drone.x - task.getX()) * (drone.x - task.getX()) + (drone.y - task.getY()) * (drone.y - task.getY()));
if (min == 0 || dis < min) {
min = dis;
index = j;
}
}
Drone drone = droneList.get(index);
drone.tindex=i;
int dx = drone.x - task.x;
int dy = drone.y - task.y;
double dsx = Math.abs(drone.speedx);
double dn = Math.abs(dx + 0.0 / dsx);//宽度/速度
double dsy = (dy / dn);
dsx = drone.x < task.x ? dsx : -dsx;
drone.runSpeedx = dsx;
drone.runSpeedy = -dsy;
drone.state = 2;
task.state = 1;
}
}
if(!taskList.isEmpty()) {
for (int i = 0; i < droneList.size(); i++) {
Drone drone = droneList.get(i);
if (drone.state == 2) {
Task task = taskList.get(drone.tindex);
if (drone.x < task.x + 80 && drone.x >= task.x || drone.y < task.y + 80 && drone.y >= task.y) {
drone.runSpeedx = 0;
drone.runSpeedy = 0;
task.blood--;
}
if (task.blood <= 0) {
drone.tindex=0;
drone.state = 0;
}
}
}
}
}
}
}
(以上代码可能会存在某些未知bug)