算法可视化教学视频上的demo感觉很有意思,就自己模仿写了一下,再添加了一个气泡间碰撞的判断(自己写的有bug,气泡生成位置重叠就会卡住)。
程序入口
import java.awt.*;
public class Main {
public static void main(String[] args) {
int sceneWidth=600,sceneHeight=600;//窗口大小
int N=10;//气泡数量
int r=20;//气泡半径
Circle[] circles=new Circle[N];//存储气泡的数组
for(int i = 0;i<N;i++){
Circle circle=new Circle( (int)(Math.random()*(sceneWidth-2*r)+r),(int)(Math.random()*(sceneHeight-2*r)+r),r,(int)(Math.random()*7-4),(int)(Math.random()*6-3));
circles[i]=circle;
}
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
AlgoFrame algoFrame=new AlgoFrame("algoframe",sceneWidth,sceneHeight);
new Thread(new Runnable() {
@Override
public void run() {
while (true){
algoFrame.render(circles);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(Circle circle:circles){
circle.move(0,sceneWidth,0,sceneHeight-25);
AlgoVisHelper.checkCircleCollision(circle,circles);
}
}
}
}).start();
}
});
}
}
绘图工具类
import java.awt.*;
import java.awt.geom.Ellipse2D;
public class AlgoVisHelper {
private AlgoVisHelper(){};
public static void setStrokeWidth(Graphics2D g2D,int width){
int strokeWidth=width;
g2D.setStroke(new BasicStroke(width,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
}
public static void setColor(Graphics2D g2D,Color color){ g2D.setColor(color);}
public static void strokeCircle(Graphics2D g2D,int x,int y,int r){
Ellipse2D cirlce=new Ellipse2D.Float(x-r,y-r,2*r,2*r);
g2D.draw(cirlce);
}
public static void fillCircle(Graphics2D g2D,int x,int y,int r){
Ellipse2D cirlce=new Ellipse2D.Float(x-r,y-r,2*r,2*r);
g2D.fill(cirlce);
}
public static void checkCircleCollision(Circle circle,Circle[] circles){//气泡间碰撞检测
for(Circle circlel:circles){
if(circle.x==circlel.x&&circle.y==circlel.y)
continue;
double a=Math.sqrt((circle.x-circlel.x)*(circle.x-circlel.x)+(circle.y-circlel.y)*(circle.y-circlel.y));
int b=(int)a;
if (a<=(circle.getR()*2)){
circle.vy=-circle.vy;
circle.vx=-circle.vx;
}
}
}
}
气泡实体类
public class Circle {
public int x;//圆的中心x坐标
public int y;//圆的中心y坐标
private int r;//圆的半径
public int vx,vy;//圆的速度
public Circle(int x,int y,int r,int vx,int vy){
this.x=x;
this.y=y;
this.r=r;
this.vx=vx;
this.vy=vy;
}
public int getR(){ return r;}
public void move(int minX,int maxX,int minY,int maxY){
x+=vx;
y+=vy;
checkBorderCollision(minX,maxX,minY,maxY);
}
public void checkBorderCollision(int minX,int maxX,int minY,int maxY){//边界碰撞检测
if (x<(minX+r)){ x=r; vx=-vx;}
if(x>=(maxX-r)){ x=maxX-r; vx=-vx;}
if (y<(minY+r)){ y=r; vy=-vy;}
if(y>=(maxY-r)){ y=maxY-r; vy=-vy;}
}
}
Frame类
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
public class AlgoFrame extends JFrame {
private int width;
private int height;
private Circle[] circles;
public AlgoFrame(String title,int width,int height){
super(title);
this.width=width;
this.height=height;
AlgoCanvas algoCanvas=new AlgoCanvas();
algoCanvas.setPreferredSize(new Dimension(width,height));
setContentPane(algoCanvas);
pack();
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public int getWidth(){return width;}
public int getHeight(){ return height;}
public void render(Circle[] circles){
this.circles=circles;
repaint();
}
private class AlgoCanvas extends JPanel{
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d=(Graphics2D)g;
//开启抗锯齿
RenderingHints renderingHints=new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2d.addRenderingHints(renderingHints);
//具体绘制
AlgoVisHelper.setStrokeWidth(g2d,2);
AlgoVisHelper.setColor(g2d,Color.BLUE);
for(Circle circle:circles){
AlgoVisHelper.strokeCircle(g2d,circle.x,circle.y,circle.getR());
}
}
@Override
public Dimension getPreferredSize(){
return new Dimension(width,height);
}
}
}