一、运用知识
1、欧拉公式:
r(t+dt)=r(t)+v(t)*dt;
v(t+dt)=v(t)+a(t)*dt;
2、多线程控制;
3、双缓冲绘图;
4、音频文件加入
二、功能实现:
1、单个烟花定点发射;
2、烟花爆炸位置、颜色、生命周期等随机;
3、加入了音效;
4、使用了双缓冲绘图
5、引入了背景图;
6、烟花燃放完自动退出界面
三、效果图
四、代码
常数类:
package com.Liao.Fireworks0728v0;
public interface Config {
public static final int SCREEN_WIDTH = 1366;//屏幕宽度
public static final int SCREEN_HEIGHT = 768;//屏幕高度
public static final int SIZE = 16;//粒子大小
public static final double DT = 0.01;//时间变量
public static final Vector_2 PSTART=new Vector_2(683,768);//粒子初始位置
public static final Vector_2 VSTART=new Vector_2(0,-500);//粒子初始速度
public static final Vector_2 ASTART=new Vector_2(0,200);//粒子初始加速度
}
二维向量类:
package com.Liao.Fireworks0728v0;
public class Vector_2 {
public double x,y;
public Vector_2(double x, double y) {
super();
this.x = x;
this.y = y;
}
//向量加法
public Vector_2 add(Vector_2 v){
return new Vector_2(this.x+v.x,this.y+v.y);
}
//向量乘法
public Vector_2 multiply(double d){
return new Vector_2(this.x*d,this.y*d);
}
}
粒子类
package com.Liao.Fireworks0728v0;
import java.awt.Color;
public class Particle {
//粒子位置、速度、加速度
public Vector_2 position, velocity, acceleration;
//粒子颜色
public Color color;
//粒子生命、年龄、宽度、长度
public int life,age,width,height;
public Particle() {
}
public int getX() {
return (int) this.position.x;
}
public int getY() {
return (int) this.position.y;
}
}
主界面
package com.Liao.Fireworks0728v0;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class MainUI extends JFrame implements Config{
private static final long serialVersionUID = 1L;
private ImageIcon p0 = new ImageIcon(this.getClass().getResource("night_sky.png"));
public static void main(String[] args) {
new MainUI().init();
}
public void init() {
//隐藏菜单栏
this.setUndecorated(true);
this.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
//添加监听器
this.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
//创建匿名对象,传递窗口(this)参数
//启动线程
new Thread(new ParticleControl(MainUI.this)).start();
//移除监听器
MainUI.this.removeMouseListener(this);
}
});
this.setVisible(true);
}
//绘制初始背景
public void paint(Graphics g) {
super.paint(g);
g.drawImage(p0.getImage(), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, null);
}
}
粒子控制
package com.Liao.Fireworks0728v0;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class ParticleControl implements Runnable, Config {
private JFrame jf;
private ImageIcon p0 = new ImageIcon(this.getClass().getResource("night_sky.png"));// 背景图片
private BufferedImage image = new BufferedImage(SCREEN_WIDTH, SCREEN_HEIGHT, BufferedImage.TYPE_INT_RGB);
private Graphics bg = image.getGraphics();
private ArrayList plist = new ArrayList();
private Sound sound = new Sound();
private Thread thread;
private int j;// 烟花发数
public ParticleControl(JFrame jf) {
super();
this.jf = jf;
// 添加音效
thread = new Thread(sound);
thread.start();
}
public void run() {
raise();
}
// 烟花上升
public void raise() {
// 20发
for (j = 0; j < 20; j++) {
// 创建粒子(烟花)
Particle rp = new Particle();
rp.position = PSTART;
rp.velocity = VSTART;
rp.acceleration = ASTART;
rp.color = new Color(255, 150, 150);
rp.width = SIZE / 2;
rp.height = SIZE;
//设定上升粒子生命周期
rp.life = 80 + new Random().nextInt(50);
for (rp.age = 1; rp.age < rp.life; rp.age++) {
// 粒子位置
rp.position = rp.position.add(rp.velocity.multiply(DT));
rp.velocity = rp.velocity.add(rp.acceleration.multiply(DT));
// 绘制粒子
bg.setColor(rp.color);
bg.drawImage(p0.getImage(), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, null);
bg.fillOval(rp.getX(), rp.getY(), rp.width, rp.height);
jf.getGraphics().drawImage(image, 0, 0, null);
try {
Thread.sleep(8);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 调用爆炸效果
bomp(rp);
}
}
// 璀璨烟花
public void bomp(Particle rp) {
//设定爆炸粒子生命周期
rp.life = 40 + new Random().nextInt(30);
for (rp.age = 1; rp.age < rp.life; rp.age++) {
for (int i = 0; i < 30; i++) {
Particle p = new Particle();
p.position = new Vector_2(rp.getX(), rp.getY());
p.velocity = new Vector_2(2, -10);
p.acceleration = particleDirection();
p.color = new Color(200 + new Random().nextInt(55), (new Random().nextInt(50) + (i + j) * 100) % 255,
new Random().nextInt(255));
p.width = SIZE / 3;
p.height = SIZE / 3;
plist.add(p);
}
bg.drawImage(p0.getImage(), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, null);
for (Particle p : plist) {
// 计算每个粒子的下一位置
p.position = p.position.add(p.velocity.multiply(DT));
p.velocity = p.velocity.add(p.acceleration.multiply(DT));
// 画到缓冲区
bg.setColor(p.color);
bg.fillOval(p.getX(), p.getY(), p.width, p.height);
}
jf.getGraphics().drawImage(image, 0, 0, null);
try {
Thread.sleep(20);
} catch (Exception ef) {
}
}
plist.clear();
jf.getGraphics().drawImage(p0.getImage(), 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, null);
// 关闭音乐
if (j == 19) {
sound.setisstop(true);
sound.getplayer().close();
//关闭窗口
jf.dispose();
}
}
// 生成一个随机方向(粒子加速度)
public static Vector_2 particleDirection() {
double theta = Math.random() * 2 * Math.PI;
return new Vector_2(100 + (Math.cos(theta) * 700), 100 + (Math.sin(theta) * 700));
}
}
音效(需要导入第三方包 jl1.0.1.jar)
package com.Liao.Fireworks0728v0;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import javazoom.jl.player.Player;
public class Sound implements Runnable {
private Boolean isstop = false;
private Player player;
public void setisstop(Boolean isstop){
this.isstop=isstop;
}
public Player getplayer(){
return player;
}
public void run() {
while (!isstop) {
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("fireworks.mp3"));
player = new Player(bis);
player.play();
} catch (Exception e) {
System.out.println("进入异常中");
// isstop=true;
// return;
}
}
}
}
就这样,一个简单的烟花就制作完成了,当然咱们还可以给烟花增加一些别的特效,后面再做更新。