From Gossip@caterpillar

Computer Graphics: 煙粒子

 

 


粒子系統的製作理念都是相同的,難是難在物理或化學等模擬,煙粒子就是如此,輕飄飄的煙動向不定,受周遭的環境而影響運動,例如風吹,在這邊是利用煙粒子重量當作風吹時的受動因子。

您可以先 看看 範例

  • Smoke.java
package onlyfun.caterpillar.graphics.particle;

import java.awt.*;
import java.applet.*;
import javax.swing.JApplet;

public class Smoke extends Applet implements Runnable {
private final int Max = 1000;
private SmokeParticle particles[]; // 煙粒子
private int appletWidth, appletHeight, xCenter, yCenter;
private Image offScreen;
private Graphics drawOffScreen;

public void init() {
setBackground(Color.black); // 背景為黑色

particles = new SmokeParticle[Max]; // 建立粒子

// 取得顯像區域
appletWidth = getSize().width;
appletHeight = getSize().height;

// 煙初始位置
xCenter = appletWidth/2;
yCenter = 2*appletHeight/3;
for(int i=0; i<Max; i++)
particles[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;

int windTime = 0;
double windX = 0;
while(true) {
drawOffScreen.clearRect(0,0,
appletWidth,appletHeight);

if(windTime <=0) {
// 風速 x
windX = 30*Math.random()-15;
// 風吹時間
windTime = (int)(20*Math.random());
}

for(int i = 0; i < Max; i++) {
if(particles[i].getState()) {
color = particles[i].getColor();

// 受風動的效果不一
double wx =
windX/particles[i].getWeight();
double x =
particles[i].getPoint().getX();
double y =
particles[i].getPoint().getY();
particles[i].getPoint().setLocation(x+wx, y);

x = particles[i].getPoint().getX();
y = particles[i].getPoint().getY();

drawOffScreen.setColor(color);
drawOffScreen.fillOval(
(int) x, (int)y, 2, 2);
particles[i].nextState();
}
}

for(int i = 0; i < Max; i++) {
if(!particles[i].getState()) {
particles[i].setLife(
(int)(255*Math.random()));
particles[i].resume(new Point(
(int)(xCenter+ Math.random()*10),
(int)(yCenter + Math.random()*10)));
}
}

// 重繪畫面
repaint();

try {
Thread.sleep(150);
}
catch (InterruptedException e) { }

windTime--;
}
}
}

class SmokeParticle {
private Point position; // 位置
private double vx, vy; // 水平與垂直速度
private double weight; // 重量
private int life; // 生命週期
private boolean state; // 狀態
private Color color; // 顏色

public void resume(Point p) {
position = p;
vx = 0;
vy = -1;
weight = 10* Math.random() + 1;
state = true;
color = new Color(life, life, life);
}

public void setLife(int life) {
this.life = life;
}

public void setWeight(double weight) {
this.weight = weight;
}

public Point getPoint() {
return position;
}

public double getWeight() {
return weight;
}

public Color getColor() {
return new Color(life, life, life);
}

public boolean getState() {
return state;
}

public void nextState() {
position.setLocation(position.getX(),
position.getY() + vy);
life -= 1;

if(life <=0) {
life = 0;
state = false;
}
}
}