版本一:錯誤示範 —— 每幀重新隨機
@Override
public void paint(Graphics g) {
for (int i = 0; i < 30; i++) {
int x = (int)(Math.random() * 1024);
int y = (int)(Math.random() * 768);
g.fillOval(x, y, 20, 20); // 每次 paint 位置全變 → 滿天亂飛
}
}

版本二:修正版 —— 固定初始座標,只更新 Y 軸
import java.awt.*;
import java.util.Random;
public class SnowFall {
public static void main(String[] args) {
Frame frame = new Frame("Snow Fall");
frame.setSize(1024, 768);
frame.setBackground(Color.BLACK);
SnowPanel panel = new SnowPanel();
frame.add(panel);
new Thread(panel).start();
frame.setVisible(true);
}
}
class SnowPanel extends Panel implements Runnable {
private static final int COUNT = 30;
private final int[] x = new int[COUNT];
private final int[] y = new int[COUNT];
private final Random r = new Random();
public SnowPanel() {
for (int i = 0; i < COUNT; i++) {
x[i] = r.nextInt(1024);
y[i] = r.nextInt(768);
}
}
@Override
public void paint(Graphics g) {
g.setColor(Color.WHITE);
for (int i = 0; i < COUNT; i++) {
g.fillOval(x[i], y[i], 20, 20);
}
}
@Override
public void run() {
while (true) {
for (int i = 0; i < COUNT; i++) {
y[i] += 2; // 下落速度
if (y[i] > 768) y[i] = 0; // 循環
}
repaint();
try { Thread.sleep(16); } catch (InterruptedException ignored) {} // ~60 FPS
}
}
}

核心修正邏輯
| 錯誤版 | 修正版 |
paint 內產生隨機座標 | 建構子一次性產生固定 x[],y[] 只在 run() 更新 |
| 雪花無軌跡、閃爍嚴重 | 每幀僅位移 Y 軸,形成連貫飄落感 |
| 無法控制速度/數量 | 陣列化管理,易擴充風力、大小、透明度等屬性 |
創意擴充方向
- 風力效果:
x[i] += windOffset,邊界反彈
- 雪花大小/速度隨機:建構子額外初始化
size[]、speed[]
- 圖片替代圓形:
g.drawImage(snowflakeImg, x[i], y[i], null)
- 雙緩衝:
BufferedImage offscreen = new BufferedImage(...) 消除閃爍
- Swing Timer 替代 Thread:EDT 安全、自動節流