天天看点

Java粒子系统(烟火篇)

用好粒子系统,自己也可以自制一场烟火!

Java粒子系统(烟火篇)

比如说这样的,这就是一个慢慢优化的过程。

下面就上代码大家仔细体会一下吧

import javax.swing.JFrame;
import javax.swing.JPanel;

public class FireWorksMain extends JPanel {
	public static void main(String[] args) {
		FireWorksMain fw = new FireWorksMain();
		fw.initUI();
	}

	public void initUI() {
		JFrame f = new JFrame();
		f.setTitle("烟花");
		f.setSize(800, 700);
		f.setDefaultCloseOperation(3);
		f.setLocationRelativeTo(null);
		f.add(this);
		f.setVisible(true);

		FireWorksThread ft = new FireWorksThread(this);
		ft.start();
	}
}
           

主函数类都很熟悉了吧

import java.awt.Color;

public class Particle {
	// 粒子的起点,速度,重力
	public VecT position, velocity, acceleration;
	public Color color;
	public double life, age, start_time;
	public int size;
	// 在界面上绘制时的x,y坐标
	public int x, y;

	public int getX() {
		return (int) position.x;
	}

	public int getY() {
		return (int) position.y;
	}
}
           

粒子类也是一样的

public class VecT {
	public double x, y;

	public VecT(double x, double y) {
		this.x = x;
		this.y = y;
	}

	// 向量加
	public VecT add(VecT p) {
		return new VecT(this.x + p.x, this.y + p.y);
	}

	// 向量乘
	public VecT multiply(double f) {
		return new VecT(this.x * f, this.y * f);
	}

}
           

向量类也不要变

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.util.ArrayList;

import javax.swing.JPanel;

public class Bomb {
	// Bomb的属性
	// 粒子的起点,速度,重力
	public VecT position, velocity, acceleration;
	public double life, age, start_time;
	public int size;
	public int x, y;
	public float alpha;

	public int getX() {
		return (int) position.x;
	}

	public int getY() {
		return (int) position.y;
	}

	public Color Bombcolor;
	// 创建粒子链表
	private ArrayList<Particle> pr = new ArrayList<>();
	// 创建颜色
	private Color color1[] = { Color.BLUE.brighter(), Color.CYAN.brighter(), Color.GRAY.brighter(),
			Color.lightGray.brighter(), Color.ORANGE.brighter(), Color.RED.brighter(), Color.ORANGE.brighter(),
			Color.magenta.brighter(), Color.YELLOW.brighter() };
	private Color color2[] = { new Color(0, 200, 20), new Color(250, 40, 40), new Color(20, 250, 60),
			new Color(110, 10, 110), new Color(10, 100, 130), new Color(250, 0, 250), new Color(0, 100, 200),
			new Color(100, 80, 250), new Color(80, 0, 0),new Color(0,0,100),new Color(0,50,200),new Color(11,151,10) };
	private int colornum1 = -1, colornum2 = -1;

	// 画分散
	public void drawscatter(Graphics g, double dt, double x, double y, JPanel panel) {
		if (colornum1 == -1 || colornum2 == -1) {
			colornum1 = (int) (Math.random() * (color1.length - 1));
			 colornum2 = (int) (Math.random() * (color2.length - 1));
//			colornum2 = (color2.length - 1);

		}
		if (pr.size() < 540) {
			for (int i = 0; i < 300; ++i) {
				Particle tp = new Particle();
				tp.position = new VecT(x, y);
				tp.velocity = sampleDirectionv2().multiply(1 - (double) (i / 30) / (double) 10);// 速度向量
				tp.acceleration = tp.velocity.multiply(0.1);
				tp.life = 7;
				tp.age = 1;
				tp.color = color1[colornum1];
				tp.size = (int) (4 + Math.random() * 3);
				pr.add(tp);
			}
			for (int i = 0; i < 300; ++i) {
				Particle tp = new Particle();
				tp.position = new VecT(x, y);
				tp.velocity = sampleDirectionv1().multiply(1 - (double) (i / 30) / (double) 20);// 速度向量
				tp.acceleration = tp.velocity.multiply(0.1);
				tp.life = 7;
				tp.age = 1;
				tp.color = color2[colornum2];
				tp.size = (int) (4 + Math.random() * 3);
				pr.add(tp);
			}
		}
		// 链表中的粒子画到缓冲区,再画到界面上
		Image image = panel.createImage(panel.getWidth(), panel.getHeight());
		Graphics2D bg = (Graphics2D) image.getGraphics();
		bg.setColor(Color.black);
		bg.fillRect(0, 0, panel.getWidth(), panel.getHeight());// 画背景
		bg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		for (int i = 0; i < pr.size(); ++i) {
			Particle p = pr.get(i);
			// 1.判断粒子的生命是否到期,到期后,从链表中移除
			if (p.age == 1)
				alpha = 1f;
			p.age += dt;
			if (p.age >= p.life) {
				pr.remove(i);
			}
			// 2.计算每个粒子的下一个位置
			p.position = p.position.add(p.velocity.multiply(dt));
			p.velocity = p.velocity.add(p.acceleration.multiply(dt));

			alpha -= 0.00019 / (double) p.life;
			bg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));// 透明度
			// 画到缓冲区
			bg.setColor(p.color);
			bg.fillOval(p.getX(), p.getY(), p.size, p.size);
		}
		// 将缓冲图片画到面板上
		g.drawImage(image, 0, 0, null);
	}

	// 生成一个随机方向烟花的
	public static VecT sampleDirectionv2() {
		double theta = Math.random() * 4 * Math.PI;
		return new VecT((12 * Math.cos(theta)), (12 * Math.sin(theta)));
	}

	// 生成一个随机方向速度
	public static VecT sampleDirectionv1() {
		double theta = Math.random() * 4 * Math.PI;
		return new VecT((20 * Math.cos(theta)), 20 * (Math.sin(theta)));
	}
}
           

创建一个bomb类爆炸效果的方法都在里面

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.util.ArrayList;

import javax.swing.JPanel;

public class FireWorksThread extends Thread {
	private static JPanel panel;
	Graphics2D g;
	// 保存粒子的队列
	private ArrayList<Bomb> bo = new ArrayList<>();
	// 起始位置
	private int startX, startY = 600;
	private boolean isadd = true;
	float alpha; // 透明度

	public FireWorksThread(JPanel panel) {
		this.panel = panel;
	}

	public void run() {
		// 时间增量
		double dt = 0.1d;
		g = (Graphics2D) panel.getGraphics();
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		while (true) {
			// 判断是否增加Bomb, 生成Bomb放入链表
			if (isadd == true) {
				Bomb bb = new Bomb();
				startX = (int) (Math.random() * (panel.getWidth() - 200) + 80);
				if (startX > panel.getWidth() - 80) {
					startX = panel.getWidth() - 80;
				}
				bb.position = new VecT(startX, startY);
				bb.velocity = new VecT(0, -35);// 速度向量
				bb.acceleration = new VecT(0, 1);
				bb.life = 16 + Math.random() * 6;
				bb.age = 1;
				bb.Bombcolor = new Color(255, 255, 255).brighter();
				bb.size = 24;
				bo.add(bb);
			}
			for (int i = 0; i < bo.size(); ++i) {
				Bomb b = bo.get(i);
				if (b.age < b.life) {
					this.drawrise(g, dt, b);
					isadd = false;
				} else {
					b.age += dt;
					b.drawscatter(g, dt, b.getX(), b.getY(), panel);
				}
				if (b.age > b.life + 6) {
					bo.remove(i);
					isadd = true;
				}
			}
			try {
				Thread.sleep(10);
			} catch (Exception ef) {
			}
		}
	}

	// 画上升
	public void drawrise(Graphics2D g, double dt, Bomb b) {
		Image image = panel.createImage(panel.getWidth(), panel.getHeight());
		Graphics2D bg = (Graphics2D) image.getGraphics();
		if (b.age == 1)
			alpha = 1;
		bg.setColor(Color.black.brighter());
		bg.fillRect(0, 0, panel.getWidth(), panel.getHeight());// 画背景

		alpha -= 0.09 / (double) b.life;
		bg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));// 透明度
		bg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// 抗锯齿
		b.position = b.position.add(b.velocity.multiply(dt));
		b.velocity = b.velocity.add(b.acceleration.multiply(dt));
		b.age += dt;
		b.Bombcolor = new Color(255, 255, 255);
		bg.setColor(b.Bombcolor);
		bg.fillOval(b.getX(), b.getY(), b.size, b.size);
		g.drawImage(image, 0, 0, null);
	}
}
           

线程类,里面也有个炸弹上升的方法!

好啦,代码可能不是很精简,很多地方可以优化,也可以改造成很多更加好看的效果,

大家可以多多尝试!