|
事實上之前的煙火在施放時並沒有煙,只有火花,可以結合兩個粒子系統來製作煙火在燃燒過程中所產生的煙硝軌跡。
在結合兩個粒子系統時,要注意,每個粒子都是獨立的,火花粒子就是火花粒子,不會與煙粒子相互影響,只不過煙粒子產生的位置是火花的目前位置,只要將位置的資訊傳遞給煙粒子物件就可以了。
指定煙粒子的方式採用比較簡單的方式,首先產生足夠的煙粒子,它們的狀態都為false,然後等待重新指定它們為復活狀態,每次繪製完火花後,在一堆煙粒子物件中尋找狀態為false的煙粒子,然後指定新的初始位置給這些粒子,如此煙粒子就會跟隨著火花的軌跡而產生了。
這邊需要之前製作的FireworkParticle與SmokeParticle類別,您可以直接看看 範例。
package onlyfun.caterpillar.graphics.particle; import java.awt.*; import javax.swing.JApplet;
public class FireworkAndSmoke extends JApplet implements Runnable { private final int fireworkMax = 200; private final int smokeMax = fireworkMax * 10; private FireworkParticle fireworkParticles[]; // 煙火粒子 private SmokeParticle smokeParticles[]; // 煙粒子 private int appletWidth, appletHeight, xCenter,yCenter; private Image offScreen; private Graphics drawOffScreen; public void init() { setBackground(Color.black); // 背景為黑色
fireworkParticles = new FireworkParticle[fireworkMax]; // 建立粒子 smokeParticles = new SmokeParticle[smokeMax]; // 取得顯像區域 appletWidth = getSize().width; appletHeight = getSize().height; // 煙火初始位置 xCenter = appletWidth/2 + (int)(Math.random()* 150 - 150); yCenter = appletHeight/2 + (int)(Math.random()* 150 - 150); for(int i = 0; i < fireworkMax; i++) fireworkParticles[i] = new FireworkParticle(); for(int i = 0; i < smokeMax; i++) { smokeParticles[i] = new SmokeParticle(); } // 建立次畫面 offScreen = createImage(appletWidth, appletHeight); drawOffScreen = offScreen.getGraphics(); } public void start() { (new Thread(this)).start(); } public void update(Graphics g) { paint(g); } public void paint(Graphics g) { g.drawImage(offScreen, 0, 0, this); } public void run() { Color color; boolean replay; while(true) { replay = true; drawOffScreen.clearRect( 0,0, appletWidth, appletHeight); for(int i = 0; i < fireworkMax; i++) { if(fireworkParticles[i].getState()) { color = fireworkParticles[i].getColor(); double x = fireworkParticles[i].getPoint().getX(); double y = fireworkParticles[i].getPoint().getY(); drawOffScreen.setColor(color); drawOffScreen.fillOval((int)x, (int)y, 1, 1); // 為煙火加上煙 for(int j = 0; j < smokeMax; j++) { if(!smokeParticles[j].getState()) { smokeParticles[j].setLife( (int)(50*Math.random())); smokeParticles[j].resume( new Point((int)x, (int)y)); break; } } fireworkParticles[i].nextState(); } } for(int j = 0; j < smokeMax; j++) { if(smokeParticles[j].getState()) { color = smokeParticles[j].getColor(); double sx = smokeParticles[j].getPoint().getX(); double sy = smokeParticles[j].getPoint().getY(); drawOffScreen.setColor(color); drawOffScreen.fillOval( (int) sx, (int) sy, 2, 2); smokeParticles[j].nextState(); } } for(int i = 0; i < fireworkMax; i++) { if(fireworkParticles[i].getState()) { replay = false; break; } } // 是否重新施放 if(replay) { // 煙火初始位置 xCenter = appletWidth/2 + (int)(Math.random()* 150 - 150); yCenter = appletHeight/2 + (int)(Math.random()* 150 - 150); for(int i = 0; i < fireworkMax; i++) { fireworkParticles[i].resume( new Point(xCenter, yCenter), fireworkMax); fireworkParticles[i].setLife( (int) (Math.random()*20)); } } // 重繪畫面 repaint(); // 暫停執行緒 150 毫秒 try { Thread.sleep(150); } catch (InterruptedException e) { } } } }
|