这是一个有javaFX2.2 写的一个礼花弹动画希望能给javaFX爱好者一下灵感!
源代码下载地址:梦续残源 http://mxcyk.com/?post=494
/**@author mxcyk.com
*一个示例,演示如何画画形状,适用于视觉
* 的影响,混合颜色重叠的对象和动画对象。
* @see javafx.scene.canvas.Canvas
* @see javafx.scene.canvas.GraphicsContext
* @see javafx.scene.effect.BlendMode
* @see javafx.scene.effect.BoxBlur
* @see javafx.scene.shape.Circle
* @see javafx.scene.Group
* @see javafx.scene.paint.LinearGradient
* @see javafx.animation.Timeline
*/
public class Fireworks extends Application {
private final SanFranciscoFireworks sanFranciscoFireworks = new SanFranciscoFireworks();
private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));
root.getChildren().add(sanFranciscoFireworks);
}
@Override public void stop() {
sanFranciscoFireworks.stop();
}
public void play() {
sanFranciscoFireworks.start();
}
public static class SanFranciscoFireworks extends Pane {
private final AnimationTimer timer;
private final Canvas canvas;
private final ImageView background;
private final List
particles = new ArrayList();
private final Paint[] colors;
private int countDownTillNextFirework = 40;
public SanFranciscoFireworks() {
// create a color palette of 180 colors
colors = new Paint[181];
colors[0] = new RadialGradient(0, 0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.WHITE),
new Stop(0.2, Color.hsb(59, 0.38, 1)),
new Stop(0.6, Color.hsb(59, 0.38, 1,0.1)),
new Stop(1, Color.hsb(59, 0.38, 1,0))
);
for (int h=0;h<360;h+=2) {
colors[1+(h/2)] = new RadialGradient(0, 0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE,
new Stop(0, Color.WHITE),
new Stop(0.2, Color.hsb(h, 1, 1)),
new Stop(0.6, Color.hsb(h, 1, 1,0.1)),
new Stop(1, Color.hsb(h, 1, 1,0))
);
}
// create canvas
canvas = new Canvas(1024, 500);
canvas.setBlendMode(BlendMode.ADD);
canvas.setEffect(new Reflection(0,0.4,0.15,0));
background = new ImageView(getClass().getResource("sf.jpg").toExternalForm());
getChildren().addAll(background,canvas);
// create animation timer that will be called every frame
// final AnimationTimer timer = new AnimationTimer() {
timer = new AnimationTimer() {
@Override public void handle(long now) {
GraphicsContext gc = canvas.getGraphicsContext2D();
// clear area with transparent black
gc.setFill(Color.rgb(0, 0, 0, 0.2));
gc.fillRect(0, 0, 1024, 708);
// draw fireworks
drawFireworks(gc);
// countdown to launching the next firework
if (countDownTillNextFirework == 0) {
countDownTillNextFirework = 10 + (int)(Math.random()*30);
fireParticle();
}
countDownTillNextFirework --;
}
};
}
public void start() { timer.start(); }
public void stop() { timer.stop(); }
/**
* 调整大小,使背景图像比例和中心。
*/
@Override protected void layoutChildren() {
// final double w = 480.0;
// final double h = 360.0;
final double w = getWidth();
final double h = getHeight();
final double scale = Math.min(w/1024d, h/708d);
final int width = (int)(1024*scale);
final int height = (int)(708*scale);
final int x = (int)((w-width)/2);
final int y = (int)((h-height)/2);
background.relocate(x, y);
background.setFitWidth(width);
background.setFitHeight(height);
canvas.relocate(x, y);
canvas.setWidth(width);
canvas.setHeight(height * 0.706);
}
private void drawFireworks(GraphicsContext gc) {
Iterator
iter = particles.iterator();
List
newParticles = new ArrayList();
while(iter.hasNext()) {
Particle firework = iter.next();
// 如果更新返回true,则粒子已过期
if(firework.update()) {
// 从这些画中删除粒子
iter.remove();
// 检查它是否应该被爆炸
if(firework.shouldExplodeChildren) {
if(firework.size == 9) {
explodeCircle(firework, newParticles);
} else if(firework.size == 8) {
explodeSmallCircle(firework, newParticles);
}
}
}
firework.draw(gc);
}
particles.addAll(newParticles);
}
private void fireParticle() {
particles.add(new Particle(
canvas.getWidth()*0.5, canvas.getHeight()+10,
Math.random() * 5 - 2.5, 0,
0, 150 + Math.random() * 100,
colors[0], 9,
false, true, true));
}
private void explodeCircle(Particle firework, List
newParticles) {
final int count = 20 + (int)(60*Math.random());
final boolean shouldExplodeChildren = Math.random() > 0.5;
final double angle = (Math.PI * 2) / count;
final int color = (int)(Math.random()*colors.length);
for(int i=count; i>0; i--) {
double randomVelocity = 4 + Math.random() * 4;
double particleAngle = i * angle;
newParticles.add(
new Particle(
firework.posX, firework.posY,
Math.cos(particleAngle) * randomVelocity, Math.sin(particleAngle) * randomVelocity,
0, 0,
colors[color],
8,
true, shouldExplodeChildren, true));
}
}
private void explodeSmallCircle(Particle firework, List
newParticles) {
final double angle = (Math.PI * 2) / 12;
for(int count=12; count>0; count--) {
double randomVelocity = 2 + Math.random() * 2;
double particleAngle = count * angle;
newParticles.add(
new Particle(
firework.posX, firework.posY,
Math.cos(particleAngle) * randomVelocity, Math.sin(particleAngle) * randomVelocity,
0, 0,
firework.color,
4,
true, false, false));
}
}
}
/**
* 绘制一个圆,一个简单的粒子。
*/
public static class Particle {
private static final double GRAVITY = 0.06;
// 动画属性和着色
double alpha;
final double easing;
double fade;
double posX;
double posY;
double velX;
double velY;
final double targetX;
final double targetY;
final Paint color;
final int size;
final boolean usePhysics;
final boolean shouldExplodeChildren;
final boolean hasTail;
double lastPosX;
double lastPosY;
public Particle(double posX, double posY, double velX, double velY, double targetX, double targetY,
Paint color,int size, boolean usePhysics, boolean shouldExplodeChildren, boolean hasTail) {
this.posX = posX;
this.posY = posY;
this.velX = velX;
this.velY = velY;
this.targetX = targetX;
this.targetY = targetY;
this.color = color;
this.size = size;
this.usePhysics = usePhysics;
this.shouldExplodeChildren = shouldExplodeChildren;
this.hasTail = hasTail;
this.alpha = 1;
this.easing = Math.random() * 0.02;
this.fade = Math.random() * 0.1;
}
public boolean update() {
lastPosX = posX;
lastPosY = posY;
if(this.usePhysics) { //一路下跌
velY += GRAVITY;
posY += velY;
this.alpha -= this.fade; // 淡出颗粒
} else { // on way up
double distance = (targetY - posY);
// ease the position
posY += distance * (0.03 + easing);
// cap to 1
alpha = Math.min(distance * distance * 0.00005, 1);
}
posX += velX;
return alpha < 0.005;
}
public void draw(GraphicsContext context) {
final double x = Math.round(posX);
final double y = Math.round(posY);
final double xVel = (x - lastPosX) * -5;
final double yVel = (y - lastPosY) * -5;
// 所有的绘图设置这种粒子的不透明度为
context.setGlobalAlpha(Math.random() * this.alpha);
// draw particle
context.setFill(color);
context.fillOval(x-size, y-size, size+size, size+size);
// draw the arrow triangle from where we were to where we are now
if (hasTail) {
context.setFill(Color.rgb(255,255,255,0.3));
context.fillPolygon(new double[]{posX + 1.5,posX + xVel,posX - 1.5},
new double[]{posY,posY + yVel,posY}, 3);
}
}
}
@Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
primaryStage.setTitle("mxcyk.com 一个漂亮的礼花弹动画");
play();
}
public static void main(String[] args) {
launch(args);
}
}