从零开始的Java桌宠(一)

从零开始的Java桌宠(一)

0.介绍

制作一个Win桌面宠物, 功能:

编写IDE: VSCode ; 语言: Java;

1. 准备工作

首先,准备好你绘制的图片,保存为支持的格式(如PNG、JPG等), 最好是透明底, 这里我用的是ps导出png格式.

2. 配置Java环境

2.1 选择Project Type

  • 使用轻量级的 VScode IDE, 并在扩展中安装插件:

    Java Extension Pack:包含了对 Java 开发的基本支持,如代码补全、调试、运行等功能。

    然后你就可以新建一个Java Project了, 新建时它会提示你选择一个Project Type:

    项目类型怎么选

  • 在 VSCode 中选择 Java 项目类型时,提示的这些选项实际上代表了不同的构建工具和框架。它们用于帮助你管理和构建项目,但对于初学者来说,理解它们的作用是有帮助的。以下是每个选项的简要介绍:

    1. No build tools(推荐)
    • 适用场景:如果你只是想快速编写一个简单的 Java 程序,没有复杂的依赖管理需求,可以选择这个选项。
    • 特点:不使用任何构建工具(比如 Maven 或 Gradle),你手动管理项目文件。适合初学者和小型项目。
    1. Maven
    • 适用场景:如果你的项目需要管理多个依赖项,或者你打算将项目发布到某个仓库,Maven 是一个非常常用的构建工具。
    • 特点
      • 自动管理依赖项。
      • 使用 pom.xml 文件来描述项目和依赖。
      • 支持构建、打包、发布等操作。
      • 对大型企业级项目非常有帮助。
    1. Gradle
    • 适用场景:与 Maven 类似,Gradle 也是一个构建工具,但它的语法更加灵活,支持多种语言的构建,通常在性能和配置灵活性上表现更好。
    • 特点
      • 比 Maven 更加现代化,支持 Groovy 或 Kotlin DSL(领域特定语言)来配置。
      • 支持增量构建和并行构建,适合更复杂的项目。
    1. JavaFX
    • 适用场景:如果你打算开发桌面应用程序(如 Java 桌宠),可以选择 JavaFX。

    • 特点

      • 专为桌面应用设计,支持图形界面、动画和用户交互。

      • 提供丰富的 UI 组件,可以用于构建现代化的桌面应用程序。

        你该选择哪个?

    • 如果你只是创建一个简单的 Java 程序或桌宠应用,并且不需要使用构建工具(例如 Maven 或 Gradle),选择 “No build tools” 就可以了。你可以直接开始编写代码,VSCode 会自动处理 Java 的编译和运行。如果你不确定,可以先选择它,这不会影响你后续的学习和开发,也可以在后期添加构建工具来优化项目管理。

    • 如果你打算使用图形界面,做桌面应用,可以选择 JavaFX,它是专门为桌面应用提供的框架,可以帮助你更容易地创建图形界面和动画。

    • 如果你以后打算扩展项目,使用构建工具(如 Maven 或 Gradle)来管理依赖,可以选择 MavenGradle

      ​ 所以这里我们先选 No build tools 就好, 选它也可以import JavaFX库.

2.2 *找不到JAVA_HOME?

  • 问题出在 Java 的安装路径和环境变量没有正确设置。即使你已经安装了 Java,但如果系统找不到 Java 的路径,通常是因为 JAVA_HOME 环境变量没有正确配置,或者 Path 环境变量中没有包括 Java 的 bin 目录。

    解决步骤

    1. 确保 Java 安装路径正确
      确认 Java 安装目录在 C:\Program Files (x86)\Java 中,例如 C:\Program Files (x86)\Java\jdk-17,检查该路径下是否有 bin 目录,其中包含 java.exejavac.exe 文件。

    2. 设置 JAVA_HOME 环境变量
      需要设置 JAVA_HOME 环境变量,让系统知道 JDK 的安装路径。

      步骤:

      • 右键点击 此电脑计算机,选择 属性
      • 点击 高级系统设置。(直接在Win搜这步就可以了)
      • 系统属性 窗口,点击 环境变量
      • 系统变量 区域,点击 新建,然后添加:
        • 变量名:JAVA_HOME
        • 变量值:JDK 的安装路径,例如:C:\Program Files (x86)\Java\jdk-17
    3. 修改 Path 环境变量
      还需要将 JAVA_HOME 路径中的 bin 目录添加到 Path 环境变量中,这样你就可以在任何地方运行 javajavac 命令。

      步骤

      • 系统变量 区域,找到并选中 Path,点击 编辑
      • 点击 新建,然后输入 %JAVA_HOME%\bin(这会自动引用你设置的 JAVA_HOME 环境变量的 bin 子目录)。
      • 确定保存所有修改。
    4. 验证环境变量设置
      完成设置后,打开一个新的 命令提示符 窗口(非常重要,因为已经打开的命令提示符不会加载新的环境变量)。(使用Win+R输入cmd打开, 而不是使用IDE中的终端)

      输入以下命令来验证:

      echo %JAVA_HOME%
      

      这应该输出你设置的 JDK 安装路径,例如:

      C:\Program Files (x86)\Java\jdk-17
      

      然后再运行:

      java -version
      javac -version
      

      如果一切配置正确,你应该能够看到 Java 和 Javac 的版本信息。

    额外注意:(反正我试了加不加引号都可以)

    • 路径中有空格的问题:你提到 Java 安装在 Program Files (x86) 下,路径中包含空格,这通常不会成为问题,只要正确设置了环境变量。如果你在设置 PathJAVA_HOME 时遇到问题,可以用双引号括起来,如:

      "C:\Program Files (x86)\Java\jdk-17"
      

    通过以上步骤,应该能够解决 “java -version” 找不到 Java 的问题。如果仍然有问题,可以确认 JDK 是否正确安装,或者重新安装 JDK。

2.3 *设置VScode终端同步cmd

我们需要确保 VSCode 的终端配置文件(settings.json)能正确加载 Java 的环境变量。

步骤

  1. 打开 VSCode 的 settings.json 文件

    • 在 VSCode 中,点击左下角的齿轮图标(设置),然后选择 Settings
    • 在右上角的搜索框中,输入 “JSON”,然后选择 Edit in settings.json,这将打开 VSCode 的配置文件。
  2. 手动配置终端环境变量: 在 settings.json 中添加以下配置来确保 JAVA_HOMEPath 环境变量在 VSCode 终端中生效:

    {
      "terminal.integrated.env.windows": {
        "JAVA_HOME": "此处是你的jdk路径",
        "Path": "此处是你的jdk路径\\bin;${env:Path}"
      }
    }
    

    这会直接在 VSCode 的终端中设置 JAVA_HOMEPath,使其指向正确的 Java 安装路径。

  3. 重启 VSCode: 配置文件更新后,重启 VSCode 并打开一个新的终端,确保新的设置生效。

** 检查 Java 环境变量**:

  • 打开 VSCode 中的终端,然后输入:

    echo $env:JAVA_HOME
    echo $env:Path
    

    检查是否能正确显示 JAVA_HOME 和包含 Java bin 目录的 Path 环境变量。

2.4 *Java下载/更新?

我之前安装的 Java6版本太老了, VScode的 Maven尝试连接的远程服务器(如 Maven 中央仓库)不再支持较旧的 SSL/TLS 协议版本. 故需要下载或者更新 Java. 这边推荐java8.

  • 方法一:

    找到 Java控制面板 它一般在和jdk文件夹同级的另一个文件夹 jre 的子文件夹 bin 里, 程序名是javacpl.exe , 双击打开即可. 然后选择更新.

  • 方法二:

    卸了重装. 就正常win卸载程序的步骤就行, 注意Oracle官网版本8往上是要收费的. 所以Java8就好.

问题
不使用Java8自带的javafx, 外配更高版本的javafx-sdk是不可以的哦. (我手动下载配置了javafx17结果报错了, 因为fx版本过高, java是不兼容的 ).

3. 先验知识

  • 基本Java语法

实现一个 “Hello, world!” 吧. 注意vscode中按Ctrl+F5实现调试.

public class Pet {
    public static void main(String[] args) {
        //Start
        System.out.println("Hello,Pet!");
    }
}
  • 基本GUI知识
显示一张图片
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Pet extends Application {
    public static void main(String[] args) {
        launch(args);  // 启动 JavaFX 应用程序
    }
    @Override
    public void start(Stage primaryStage) {
        // 创建一个图片视图对象
        Image image = new Image("file:/D:/WORK/Unity/Pet/Pet.jpg");  // 你的图片路径
        ImageView imageView = new ImageView(image);
        
        // 将图片放到一个容器中
        StackPane root = new StackPane();
        root.getChildren().add(imageView);

        // 创建场景并设置到舞台
        Scene scene = new Scene(root, 300, 250);
        primaryStage.setTitle("My Java Pet");
        primaryStage.setScene(scene);

        // 显示窗口
        primaryStage.show();
    }
}
调整图片大小
// 调整图片大小
        imageView.setFitWidth(300);  // 设置图片的宽度
        imageView.setFitHeight(250); // 设置图片的高度
        imageView.setPreserveRatio(true); // 保持图片的纵横比
调整原始图片比例:
        // 调整图片大小为原尺寸的八分之一
        imageView.setFitWidth(image.getWidth() /8 );
        imageView.setFitHeight(image.getHeight() / 8);
        imageView.setPreserveRatio(true); // 保持图片的纵横比
设置窗口大小适应屏幕: (下面是一处定义变量, 两处修改)
import javafx.stage.Screen;

		// 获取屏幕尺寸
        double screenWidth = Screen.getPrimary().getVisualBounds().getWidth();
        double screenHeight = Screen.getPrimary().getVisualBounds().getHeight();
        
        // 设置初始位置
        double initialY = screenHeight / 2 - imageView.getFitHeight() / 2;
        imageView.setY(initialY);
        
        // 创建场景并设置到舞台
        Scene scene = new Scene(root, screenWidth, screenHeight);
图片上下移动:

使用 JavaFX 的 TimelineKeyFrame 来实现简单的动画效果。例如,可以让你的桌宠图片上下移动,或者实现其他的动画效果。

        // 定义动画的方向和移动速度
        boolean[] movingDown = {true};
        double moveAmount = 10; // 每次移动的像素值

        // 创建动画:每隔10毫秒更新一次位置
        Timeline timeline = new Timeline(
                new KeyFrame(Duration.millis(10), event -> {
                    if (movingDown[0]) {
                        System.out.println("Moving Down");
                        imageView.setY(imageView.getY() + moveAmount);
                        // 当到达底部边界时改变方向
                        if (imageView.getY() >= 250 - imageView.getFitHeight()) {
                            movingDown[0] = false;
                        }
                    } else {
                        System.out.println("Moving Up");
                        imageView.setY(imageView.getY() - moveAmount);
                        // 当到达顶部边界时改变方向
                        if (imageView.getY() <= 0) {
                            movingDown[0] = true;
                        }
                    }
                })
        );
        timeline.setCycleCount(Timeline.INDEFINITE);  // 无限循环
        timeline.setRate(0.1);  // 动画速率
        timeline.play();  // 播放动画

        // 将图片放到一个容器中
        Pane root = new Pane();
        root.getChildren().add(imageView);
*图片不移动?

解决方案: 容器的格式不要选择StackPane, 而选择Pane.

在 JavaFX 中,StackPanePane 是不同类型的布局容器,它们的布局策略不同,这就是使用 StackPane 导致图片看似没有移动的原因:

StackPane 的布局策略

StackPane 会将所有子节点堆叠在一起,并将它们对齐到容器的中心。当你通过代码改变子节点(如 ImageView)的 y 坐标时,StackPane 会尝试重新将子节点对齐到中心位置,从而覆盖了你手动设置的 y 坐标变化。也就是说,你在代码里让图片上下移动,但 StackPane 会不断地把图片拉回到中心位置,这样图片就好像没有移动一样。

Pane 的布局策略

Pane 是一个非常简单的布局容器,它不会对子节点进行任何布局调整。当你将子节点添加到 Pane 中时,子节点会保持你设置的位置和大小。所以,当你通过代码改变 ImageViewy 坐标时,Pane 不会干扰这个变化,图片就能按照你的代码逻辑正常上下移动。

去掉窗口:
// 设置舞台样式为无装饰,去掉窗口边框, 且设置背景为透明色
     scene.setFill(Color.TRANSPARENT);
     primaryStage.initStyle(StageStyle.TRANSPARENT);

右击图片显示 exit 按键, 退出桌宠:

使用 JavaFX 的 ContextMenu 组件。ContextMenu 是一个弹出式菜单,通常在用户右键单击时显示。

         // 创建右键菜单
        ContextMenu contextMenu = new ContextMenu();
        MenuItem exitMenuItem = new MenuItem("Exit");
        exitMenuItem.setOnAction(e -> {
            primaryStage.close(); // 关闭舞台,退出程序
        });
        contextMenu.getItems().add(exitMenuItem);
        // 为图片视图添加右键菜单事件处理
        imageView.setOnContextMenuRequested(e -> {
            contextMenu.show(imageView, e.getScreenX(), e.getScreenY());
        });

动画消失一会儿, 播放一会儿, 周期循环: (注意这里的movementTimeline代替了上文的Timeline)

//注意这里的movementTimeline代替了上文的Timeline, 所以定义处要做修改, 这里没写, 如下所示
//movementTimeline = new Timeline(...

		movementTimeline.setCycleCount(Timeline.INDEFINITE);  // 无限循环
        movementTimeline.play(); // 初始时暂停移动动画

        // 创建显示和隐藏的时间线
        appearanceTimeline = new Timeline(
                new KeyFrame(Duration.seconds(2), event -> {
                    System.out.println("Showing image and starting movement");
                    imageView.setVisible(false); // 隐藏图片
                    movementTimeline.pause(); // 暂停移动动画
                }),
                new KeyFrame(Duration.seconds(3), event -> {
                    System.out.println("Hiding image and pausing movement");
                    imageView.setVisible(true); // 显示图片
                    movementTimeline.play(); // 开始移动动画
                })
        );
        appearanceTimeline.setCycleCount(Timeline.INDEFINITE);
        appearanceTimeline.play();
实现宠物具有 “重力” 效果

即悬空时停止上下移动动画并往下掉落,直到接触屏幕底部边缘:

实现思路

  1. 添加重力逻辑:在动画循环中,当宠物处于悬空状态时,使其 Y 坐标以一定速度增加,模拟下落效果。
  2. 检测底部边缘:在下落过程中,检查宠物是否接触到屏幕底部边缘,如果接触到则停止下落。
  3. 暂停上下移动动画:当宠物开始下落时,暂停之前的上下移动动画。
private Timeline gravityTimeline;
    
    double gravitySpeed = 3.5; // 重力下落速度
    
    // 检查是否悬空,若悬空则切换到重力动画, 这段添加在总移动动画的else{}后面
    if (imageView.getY() < screenHeight - imageView.getFitHeight()-15) {
    	movementTimeline.pause();
        gravityTimeline.play();
    }
        // 创建重力动画
        gravityTimeline = new Timeline(
                new KeyFrame(Duration.millis(20), event -> {
                    double newY = imageView.getY() + gravitySpeed;
                    if (newY <= screenHeight - imageView.getFitHeight()) {
                        imageView.setY(newY);
                    } else {
                        gravityTimeline.pause(); // 到达底部,停止下落
                        movementTimeline.play(); // 回到底部后恢复移动动画
                    }
                })
        );

        /*最后记得在时间线那里
        gravityTimeline.play(); // 开始重力动画 和
        gravityTimeline.pause(); // 暂停重力动画 
        */
设置桌宠始终置顶, 不被其他程序窗口遮挡:
primaryStage.setAlwaysOnTop(true); // 设置舞台始终置顶
鼠标拖拽Ta:
import javafx.scene.input.MouseEvent;

    private double mouseXOffset;
    private double mouseYOffset;
    
       // 添加鼠标拖动功能
               imageView.setOnMousePressed((MouseEvent event) -> {
                mouseXOffset = event.getSceneX() - imageView.getX();
                mouseYOffset = event.getSceneY() - imageView.getY();
                movementTimeline.pause();
                gravityTimeline.pause();
            });
    
            imageView.setOnMouseDragged((MouseEvent event) -> {
                double newX = event.getSceneX() - mouseXOffset;
                double newY = event.getSceneY() - mouseYOffset;
    
                // 限制宠物在屏幕范围内移动
                newX = Math.max(0, Math.min(newX, screenWidth - imageView.getFitWidth()));
                newY = Math.max(0, Math.min(newY, screenHeight - imageView.getFitHeight()));
    
                imageView.setX(newX);
                imageView.setY(newY);
            });

            imageView.setOnMouseReleased((MouseEvent event) -> {
                // 释放鼠标后检查是否悬空,若悬空则启动重力动画
                if (imageView.getY() < screenHeight - imageView.getFitHeight()) {
                    movementTimeline.pause();
                    gravityTimeline.play();
                } else {
                    movementTimeline.play();
                }
            });

​ by xc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值