JAVA中的多线程与运动仿真(1)——用JAVA来放一场烟花
一.实现效果的简单展示:
初步实现的动态效果为在鼠标点击之后,点击之处出现一簇小球,然后向不同方向散开变大。
利用这一效果,再在后续增加颜色渐变的效果,增加小球的数量,降低大小即可实现逼真的烟花特效。
二.代码实现的简单分析
1.创建窗体
由于画笔对象需要在窗体上获取,并且后续的小球等图像的绘制也需要在窗体上进行,所以在整个项目的开始阶段应当首先利用例如JFrame类来创建,调试好窗体。
2.绘制与移动小球
在导入java.awt.Graphics包后,从窗体上获取到画笔(Graphics)对象即可开始调用相关方法。
假设我已经获取到了画笔对象:g
在使用g调用setcolor方法设置颜色后即可调用fillOval方法来绘制一个特定位置与大小的圆形:
例如:g.fillOval(100,200,60,70)便是绘制一个左上顶点坐标为(100,200)长60,高70的长方形的内切圆
绘制好圆形后,再次使用g调用fillOval方法,但是改变绘制的坐标即可实现小球平面位置的移动。
但是,由于移动前后的小球位于同一个图层上,从视觉的直观感受上我们只会感觉一下绘制了多个小球,或者绘制了一个不断增长的柱形。
因此,在绘制新的位置的小球时,应重新设置颜色,再调用fillRect方法绘制实心矩形来实现对上一个图层的擦除。
同时,即便如此,小球的绘制速度也太快了,呈现出来的是小球一闪而过,因此要调用Thread.sleep(x)
函数[其中x为线程暂停的时间,单位为毫秒ms]来使得人眼能够捕捉到小球的运动。
此时,单个小球的简单运动就完成了。
3.利用线程解决小球频闪问题
在第二步完成之后,当小球数量较多,甚至仅仅是两个时,小球的显示就不会像原来只有一个小球时的那样清楚连贯,而是出现间歇性闪烁,这是因为在小球创建多了之后,有多个线程,但是却仅有一个窗体,此时多个线程在操作一个窗体对象,各个线程在不断的在执行擦除操作,因而导致了小球的闪烁现象。
解决这一问题最好的办法便是防止同时启动多个线程,而是将新创建的小球放入队列中,由一个线程来同时进行操作。
三.代码实现部分
①.Ball.java
import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;
public class Ball implements Mover{
Color color1 = new Color(250,220,74);
Random Ran = new Random();
//小球运动步长
float x_length = 5;
float y_length = 5;
int size = 10;
int i=1;
//小球初始速度的方向
float vx = (2*Ran.nextFloat()-1)*x_length;
float vy = (2*Ran.nextFloat()-1)*y_length;
//小球加速度
float acce = (float) 1.1;
//小球初始误差中心坐标
public float x,y;
public Ball(int x, int y){
this.x=x;
this.y=y;
}
public void move() {
vx *= acce;
vy *= acce;
x += vx;
y += vy;
size += 3;
i=i+1;
}
public void draw(Graphics g) {
g.setColor(Color.ORANGE);
g.fillOval((int) x,(int) y, size, size);
}
}
②.drawboard.java
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.*;
import java.util.ArrayList;
import java.util.Random;
class drawboard{
public static void main(String[] args){
drawboard itUI = new drawboard();
itUI.ShowUI();
}
public ArrayList<Mover> MoverList = new ArrayList<>();
public void ShowUI(){
JFrame DrawBoard = new JFrame();
//窗体基本配置
DrawBoard.setTitle("烟花特效");
DrawBoard.setSize(1600,1000);
DrawBoard.setLocationRelativeTo(null);
DrawBoard.setDefaultCloseOperation(3);
DrawBoard.setLayout(new FlowLayout());
//添加鼠标监听器
drawmouse Mouse = new drawmouse(MoverList);
DrawBoard.addMouseListener(Mouse);
DrawBoard.setVisible(true);
Graphics g = DrawBoard.getGraphics();
//运行线程
drawthread dt = new drawthread(MoverList,g);
dt.start();
System.out.println("启动");
// Mouse.g = g;
}
}
③.drawmouse.java
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class drawmouse extends MouseAdapter{
public int x,y;
public ArrayList<Mover> MoverList;
public drawmouse(ArrayList<Mover> MoverList){
this.MoverList = MoverList;
}
//鼠标点击一下,放一个飞机进入队列
public void mouseClicked(MouseEvent e){
x=e.getX();
y=e.getY();
for(int i=0;i<=20;i++){
Ball nBall = new Ball(x,y);
MoverList.add(nBall);
}
}
}
④.drawthread.java
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
public class drawthread extends Thread{
public Graphics g;
Random ran = new Random();
public ArrayList<Mover> MoverList;
public drawthread(ArrayList<Mover> MoverList,Graphics g){
this.MoverList = MoverList;
this.g = g;
}
public void run(){
while(true){
//休眠50秒
try {
Thread.sleep(50);
} catch (Exception ef) {
}
//刷新背景
g.setColor(Color.WHITE);
g.fillRect(0, 0, 1800, 1200);
//移动一下队列中所有球,再画一下队列中所有小球
System.out.println("T----线程把队列中所有小球画移了一次");
for(int i=0;i<MoverList.size();i++) {
//得到队列中的一个小球
Mover Mover=MoverList.get(i);
Mover.move();
Mover.draw(g);
}
}
}
}
⑤.Mover.java
import java.awt.Graphics;
public interface Mover {
public void move();
public void draw(Graphics g);
}