【JAVAFX】在屏幕上出现旋转随机小彩球效果

发布于:2025-03-12 ⋅ 阅读:(15) ⋅ 点赞:(0)

直接上代码

package sample;

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

// 主类,继承自Application,是JavaFX应用程序的入口
public class Main extends Application {
    // 定义常量,表示火花的数量为100个
    private static final int SPARK_COUNT = 100;
    // 用于存储所有火花对象的列表
    private List<Spark> sparks = new ArrayList<>();
    // 用于绘图的画布对象
    private Canvas canvas;
    // 绕X轴的旋转角度,初始化为0
    private double rotationAngleX = 0;
    // 绕Y轴的旋转角度,初始化为0
    private double rotationAngleY = 0;
    // 旋转速度,用于控制角度的变化速率
    private double rotationSpeed = 0.01;
    //在屏幕的什么范围内生成
    private Integer xZone=1920;
    private Integer yZone=1000;

    // JavaFX应用程序启动时调用的方法
    @Override
    public void start(Stage primaryStage) throws Exception {
        // 创建一个根节点Group,用于组织场景中的所有节点
        Group root = new Group();
        // 创建一个宽度为800,高度为600的画布
        canvas = new Canvas(xZone, yZone);
        // 将画布添加到根节点中
        root.getChildren().add(canvas);

        // 循环创建100个火花对象,并添加到sparks列表中
        for (int i = 0; i < SPARK_COUNT; i++) {
            sparks.add(new Spark(xZone,yZone));
        }

        // 创建一个动画定时器,用于定时更新和绘制画面
        AnimationTimer timer = new AnimationTimer() {
            // 每次定时器触发时调用的方法
            @Override
            public void handle(long now) {
                // 获取画布的绘图上下文,用于绘制图形
                GraphicsContext gc = canvas.getGraphicsContext2D();
                // 清空画布上的内容
                gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());

                // 保存当前的绘图状态,以便后续恢复
                gc.save();

                // 将绘图原点平移到画布的中心
                gc.translate(canvas.getWidth() / 2, canvas.getHeight() / 2);

                // 增加绕X轴和Y轴的旋转角度
                rotationAngleX += rotationSpeed;
                rotationAngleY += rotationSpeed;

                // 遍历所有的火花对象
                for (Spark spark : sparks) {
                    // 更新火花的状态(例如透明度)
                    spark.update();
                    // 计算火花在3D空间中的初始坐标(相对于画布中心的偏移)
                    double x3d = spark.x - canvas.getWidth() / 2;
                    double y3d = spark.y - canvas.getHeight() / 2;
                    double z = spark.depth;

                    // 进行绕X轴的旋转计算,更新Y和Z坐标
                    double newY = y3d * Math.cos(rotationAngleX) - z * Math.sin(rotationAngleX);
                    z = y3d * Math.sin(rotationAngleX) + z * Math.cos(rotationAngleX);
                    y3d = newY;

                    // 进行绕Y轴的旋转计算,更新X和Z坐标
                    double newX = x3d * Math.cos(rotationAngleY) + z * Math.sin(rotationAngleY);
                    z = -x3d * Math.sin(rotationAngleY) + z * Math.cos(rotationAngleY);
                    x3d = newX;

                    // 计算透视变换的因子,用于模拟3D效果
                    double factor = 1000.0 / (1000.0 + z);
                    // 计算在屏幕上的X坐标
                    double screenX = x3d * factor + canvas.getWidth() / 2;
                    // 计算在屏幕上的Y坐标
                    double screenY = y3d * factor + canvas.getHeight() / 2;
                    // 计算在屏幕上显示的火花大小
                    double size = spark.size * factor;

                    // 设置绘图颜色,根据火花的颜色和透明度进行调整
                    gc.setFill(spark.color.deriveColor(0, 1, 1, spark.alpha));
                    // 在计算后的坐标位置绘制火花(一个椭圆)
                    gc.fillOval(screenX - size / 2, screenY - size / 2, size, size);
                }

                // 移除透明度为0(即已经消失)的火花
                sparks.removeIf(spark -> spark.alpha == 0);
                // 如果火花数量不足100个,添加新的火花
                while (sparks.size() < SPARK_COUNT) {
                    sparks.add(new Spark(xZone,yZone));
                }

                // 恢复之前保存的绘图状态
                gc.restore();
            }
        };

        // 启动动画定时器
        timer.start();

        // 设置窗口的样式为透明
        primaryStage.initStyle(StageStyle.TRANSPARENT);
        // 创建一个场景,包含根节点,宽度为800,高度为600,背景透明
        Scene scene = new Scene(root, xZone, yZone, Color.TRANSPARENT);
        // 将场景设置到主舞台上
        primaryStage.setScene(scene);
        // 显示主舞台
        primaryStage.show();
    }

    // 应用程序的入口点,启动JavaFX应用程序
    public static void main(String[] args) {
        launch(args);
    }
}

// 火花类,用于表示一个火花对象
class Spark {
    // 火花在画布上的X坐标
    double x;
    // 火花在画布上的Y坐标
    double y;
    // 火花的大小
    double size;
    // 火花的颜色
    Color color;
    // 火花的透明度
    double alpha;
    // 火花在3D空间中的深度值
    double depth;

    // 构造方法,用于初始化火花的属性
    public Spark(int xZone,int yZone) {
        Random random = new Random();
        // 随机生成X坐标,范围在0到800之间
        x = random.nextInt(xZone);
        // 随机生成Y坐标,范围在0到600之间
        y = random.nextInt(yZone);
        // 随机生成大小,范围在2到102之间
        size = random.nextDouble() * 100 + 10;
        // 随机生成颜色
        color = Color.color(random.nextDouble(), random.nextDouble(), random.nextDouble());
        // 初始透明度为1.0(完全不透明)
        alpha = 1.0;
        // 随机生成深度值,范围在0到1000之间
        depth = random.nextDouble() * 1000;
    }

    // 更新火花状态的方法,主要是减少透明度
    public void update() {
        alpha -= 0.01;
        if (alpha < 0) {
            alpha = 0;
        }
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到