上次我们完成了在窗体上绘制无人机,使其不断运动并能触边反弹的demo,这次我们继续优化升级,实现通过点击按钮生成无人机和入侵者,且当无人机检测到入侵者时会将其消灭等功能。
功能实现
1、点击按钮生成无人机或入侵者
既然要通过点击按钮的方式批量产生无人机和入侵者,而且无人机和入侵者本身有很多的属性和方法,所以我们首先就需要把无人机和入侵者分别封装成一个类,然后在点击按钮的时候创建一个对象,添加到数组中保存起来。
①封装
无人机的属性包括其坐标、核心大小、整体大小、雷达扫描区域大小等等,方法包括移动和绘制。基于上次我们写的demo,我们只需要把对应部分的代码写到类的方法里面就可以了,入侵者同理,根据自己的想法绘制即可,这里采用黑色实心圆和一个红圈的图案。
②添加按钮
我们可以在窗体上添加两个JPanel,一个放在中间用于主界面,一个放在南边包含按钮。然后,在南边的窗体上添加"生成无人机"和"生成入侵者"两个JButton。
接着,我们就需要写一个监听器类,实现动作监听器的接口。然后,再重写的方法里面获取按钮的内容,如果是"生成无人机",就创建一个对象并传入必要的参数,并将这个对象保存到一个动态数组中,方便统一在线程中调用绘制。(生成入侵者同理)
最后,将按钮绑定监听器类即可。
③绘制和移动
在上面的操作中,我们已经将所有生成的无人机和入侵者添加到动态数组中了,接下来要在线程中取出里面的对象并循环调用里面的方法。
首先,我们可以在UI类里面进行引用传递,将监听器类里面的两个动态数组传到线程类中(因为UI类同时创建了监听器类和线程类的对象)。
接着,我们写一个死循环,里面再写两个循环遍历无人机数组和入侵者数组,调用他们的绘制和移动方法即可。
2、无人机检测并消灭入侵者
主体的思路是当无人机在其雷达扫描的区域发现入侵者,则该入侵者就会从数组中被删除,从而从界面上消失。
①检测入侵者
前面我们提到设置的入侵者是黑色实心圆,所以在与无人机相遇时必然会导致区域颜色的变化,我们就可以利用这一变化来实现检测。
首先,我们通过嵌套循环遍历无人机整个雷达扫描区域的坐标点,并调用方法getRGB()获取画布上这个坐标点的RGB的值(传入参数为横纵坐标,返回值是一个int)。
接着,创建一个Color类的对象,将这个RGB值作为参数传入,再通过对象调用getRed()、getGreen()、getBlue()方法获取三个具体的值。
最后,如果这三个值加起来除以3后小于10,则可以认为检测到了入侵者。
②消灭入侵者
这就是一个典型的数学几何问题,即当入侵者和无人机的扫描区域圆外切、内含、内切、相交等情况出现时,就可以判定该入侵者被无人机攻击并消灭了。
我们现在数组中存着入侵者的对象,我们遍历他们,获取他们的坐标和大小,再通过判断条件:两圆圆心距离<=入侵者半径+无人机扫描区域半径,即可认为该入侵者被消灭,将其从数组中删除即可。
完整代码
droneUI类
java
import javax.swing.*;
import java.awt.*;
public class droneUI extends JFrame {
public droneUI(){
setTitle("智能无人机平台");
setSize(1200,1000);
setDefaultCloseOperation(3);
setLocationRelativeTo(null);
JPanel jp1=new JPanel();
JPanel jp2=new JPanel();
JButton jb1=new JButton("生成无人机");
JButton jb2=new JButton("生成入侵者");
jp1.setBackground(Color.gray);
add(jp1,BorderLayout.SOUTH);
add(jp2,BorderLayout.CENTER);
jp1.add(jb1);
jp1.add(jb2);
DroneListener dl=new DroneListener();
jb1.addActionListener(dl);
jb2.addActionListener(dl);
setVisible(true);
Graphics g=jp2.getGraphics();
droneThread dt=new droneThread(g);
dt.droneList=dl.droneList;
dt.invaderList=dl.invaderList;
dt.start();
}
public void paint(Graphics g){
super.paint(g);
}
public static void main(String[] args) {
new droneUI();
}
}
droneThread类
java
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
public class droneThread extends Thread {
Graphics g;
ArrayList<Drone> droneList = new ArrayList<>();
ArrayList<Invader> invaderList = new ArrayList<>();
public droneThread(Graphics g) {
this.g = g;
}
public void run() {
while (true) {
BufferedImage img = new BufferedImage(1200, 1000, 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 i = 0; i < droneList.size(); i++) {
droneList.get(i).draw(bg);
droneList.get(i).move();
}
for (int i = 0; i < invaderList.size(); i++) {
invaderList.get(i).draw(bg);
invaderList.get(i).move();
}
if (!droneList.isEmpty()) {
for (int i = 0; i < droneList.size(); i++) {
Drone drone = droneList.get(i);
for (int j = drone.x; j < drone.x + drone.scanSize; j++) {
for (int k = drone.y; k < drone.y + drone.scanSize; k++) {
int ColorNum = img.getRGB(j, k);
Color c = new Color(ColorNum);
if ((c.getRed() + c.getGreen() + c.getBlue()) / 3 < 10) {
for (int l = 0; l < invaderList.size(); l++) {
Invader iv=invaderList.get(l);
int dx=drone.x-iv.x;
int dy=drone.y-iv.y;
//算出两圆心之间的距离
double distance=Math.sqrt(dx*dx+dy*dy);
double standard=drone.scanSize+iv.size;
if(distance<standard){
invaderList.remove(l);
}
}
}
}
}
}
}
g.drawImage(img, 0, 0, null);
try {
Thread.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
Drone类
java
import java.awt.*;
public class Drone {
int x,y,speedX,speedY,scanSize,size;
int status;
int coreSize;
public Drone(int x,int y,int speedX,int speedY,int status){
this.x=x;
this.y=y;
this.speedX=speedX;
this.speedY=speedY;
this.status=status;
coreSize=15;
size=30;
scanSize=100;
}
public void draw(Graphics bg){
Color color1=new Color(0,0,255,60);
bg.setColor(color1);
bg.fillOval(x,y,scanSize,scanSize);
Color color2=new Color(64, 195, 66);
bg.setColor(color2);
bg.fillOval(x+35,y+35,size,size);
Color color3=new Color(255,0,0);
bg.setColor(color3);
bg.fillOval(x+42,y+42,coreSize,coreSize);
}
public void move(){
if(x>300+600||x<200){
speedX=-speedX;
}
if(y>500+175||y<175){
speedY=-speedY;
}
x+=speedX;
y+=speedY;
}
}
DroneListener类
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=new ArrayList<>();
ArrayList<Invader> invaderList=new ArrayList<>();
@Override
public void actionPerformed(ActionEvent e) {
Random ran=new Random();
String name=e.getActionCommand();
if(name.equals("生成无人机")){
int x=ran.nextInt(700)+200;
int y=ran.nextInt(500)+175;
int speedX=ran.nextInt(5)-2;
int speedY=ran.nextInt(5)-2;
Drone drone=new Drone(x,y,speedX,speedY,0);
droneList.add(drone);
} else if (name.equals("生成入侵者")) {
int x=ran.nextInt(1150);
int y=ran.nextInt(905);
int speedX=ran.nextInt(5)-2;
int speedY=ran.nextInt(5)-2;
Invader iv=new Invader(x,y,speedX,speedY,0);
invaderList.add(iv);
}
}
}
Invader类
java
import java.awt.*;
public class Invader {
int x, y, speedX, speedY, size;
int blood, status;
public Invader(int x, int y, int speedX, int speedY, int status) {
this.x = x;
this.y = y;
this.speedX = speedX;
this.speedY = speedY;
blood = 100;
size = 30;
this.status = status;
}
public void draw(Graphics bg) {
if (blood <= 0) {
return;
}
bg.setColor(Color.black);
bg.fillOval(x, y, size, size);
bg.setColor(Color.RED);
bg.drawOval(x - 1, y - 1, size + 2, size + 2);
}
public void move() {
if (blood <= 0) {
return;
}
if (x > 1200 - size || x < 0) {
speedX = -speedX;
}
if (y > 950 - size || y < size) {
speedY = -speedY;
}
x += speedX;
y += speedY;
}
}