You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX卡片配对游戏开发求助:实现卡片赋值匹配与点击显示ArrayList中图片功能

搞定你的JavaFX卡片配对游戏!

嘿,我来帮你一步步实现卡片数值匹配和点击显示图片的功能,咱们尽量用简单易懂的方式改代码,适合编程新手理解~

核心思路梳理

首先,咱们要解决两个核心问题:

  • 给每张卡片绑定一个「配对数值」:这样点击两张卡片后能对比数值判断是否匹配
  • 点击卡片时切换显示正面图片:从列表里取出对应图片替换卡片背面

我会把你的代码重构得更简洁,同时实现这两个功能,每一步都给你讲清楚~


第一步:创建Card类封装卡片信息

咱们先做一个简单的Card类,把每张卡片的图片路径和配对数值放在一起,这样后续对比的时候直接拿数值就行,不用从图片名里抠,更直观:

// 这个类用来存每张卡片的信息:图片路径和配对用的数值
class Card {
    private String imagePath; // 卡片正面图片的路径
    private int matchValue;  // 配对数值,比如2和2是一对,3和3是一对

    // 构造方法,创建Card对象时传入图片路径和数值
    public Card(String imagePath, int matchValue) {
        this.imagePath = imagePath;
        this.matchValue = matchValue;
    }

    // 获取图片路径的方法
    public String getImagePath() {
        return imagePath;
    }

    // 获取配对数值的方法
    public int getMatchValue() {
        return matchValue;
    }
}

第二步:重构你的主代码

我把原来的代码重构了,去掉重复的按钮变量,用列表管理所有卡片按钮,同时实现配对逻辑:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.geometry.Pos;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.util.Duration;
import javafx.animation.PauseTransition;
import java.util.ArrayList;
import java.util.Collections;

public class FinalProject extends Application {
    // 卡片背面的图片和ImageView
    private Image backCard;
    private ImageView backCardView;

    // 用来存所有卡片按钮的列表,不用单独写button1、button2啦
    private ArrayList<Button> cardButtons = new ArrayList<>();
    // 用来存所有卡片的信息(图片+数值)
    private ArrayList<Card> cardList = new ArrayList<>();

    // 记录当前翻转的两张卡片:按钮和对应的Card对象
    private Button flippedButton1 = null;
    private Card flippedCard1 = null;
    private Button flippedButton2 = null;
    private Card flippedCard2 = null;

    // 标记是否正在处理配对(防止同时点多张卡片)
    private boolean isProcessing = false;

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        // 初始化卡片背面图片
        backCard = new Image("file:backCard.jpg");
        backCardView = new ImageView(backCard);
        backCardView.setFitWidth(100);
        backCardView.setPreserveRatio(true);

        // 初始化卡片列表:把图片和对应的配对数值绑定
        cardList.add(new Card("2_Clubs.jpg", 2));
        cardList.add(new Card("2_Diamonds.jpg", 2)); // 和上面的2配对
        cardList.add(new Card("3_Clubs.jpg", 3));
        cardList.add(new Card("3_Diamonds.jpg", 3)); // 和上面的3配对
        // 洗牌,打乱卡片顺序
        Collections.shuffle(cardList);

        // 创建网格布局
        GridPane gridpane = new GridPane();
        gridpane.setAlignment(Pos.CENTER);
        gridpane.setHgap(20); // 按钮之间的水平间距
        gridpane.setVgap(20); // 按钮之间的垂直间距

        // 创建4个卡片按钮,添加到网格和列表里
        for (int i = 0; i < 4; i++) {
            Button cardButton = new Button();
            cardButton.setGraphic(backCardView); // 默认显示背面
            // 给每个按钮绑定对应的Card对象(用userData存,方便点击时取)
            cardButton.setUserData(cardList.get(i));
            // 添加点击事件
            cardButton.setOnAction(new CardClickHandler());
            // 添加到按钮列表和网格
            cardButtons.add(cardButton);
            // 布局位置:第0行放前两个,第1行放后两个
            gridpane.add(cardButton, i % 2, i / 2);
        }

        // 创建场景并显示
        Scene scene = new Scene(gridpane);
        primaryStage.setScene(scene);
        primaryStage.setTitle("Matching Game");
        primaryStage.show();
    }

    // 自定义的点击事件处理器,所有卡片按钮共用这个逻辑
    private class CardClickHandler implements EventHandler<ActionEvent> {
        @Override
        public void handle(ActionEvent event) {
            // 如果正在处理配对(比如两张卡片翻了还没判断),直接返回
            if (isProcessing) {
                return;
            }

            // 获取当前点击的按钮和对应的Card对象
            Button clickedButton = (Button) event.getSource();
            Card clickedCard = (Card) clickedButton.getUserData();

            // 如果点击的是已经翻转的卡片,直接返回(避免重复点击)
            if (clickedButton == flippedButton1 || clickedButton == flippedButton2) {
                return;
            }

            // 显示卡片正面:创建ImageView并设置到按钮上
            Image frontImage = new Image("file:" + clickedCard.getImagePath());
            ImageView frontView = new ImageView(frontImage);
            frontView.setFitWidth(100);
            frontView.setPreserveRatio(true);
            clickedButton.setGraphic(frontView);

            // 处理翻转逻辑
            if (flippedButton1 == null) {
                // 这是第一张翻转的卡片,记录下来
                flippedButton1 = clickedButton;
                flippedCard1 = clickedCard;
            } else {
                // 这是第二张翻转的卡片,开始判断是否匹配
                flippedButton2 = clickedButton;
                flippedCard2 = clickedCard;
                isProcessing = true; // 标记正在处理,防止后续点击

                // 对比两张卡片的配对数值
                if (flippedCard1.getMatchValue() == flippedCard2.getMatchValue()) {
                    // 匹配成功:禁用这两个按钮,不让再点击
                    flippedButton1.setDisable(true);
                    flippedButton2.setDisable(true);
                    // 清空记录
                    flippedButton1 = null;
                    flippedButton2 = null;
                    flippedCard1 = null;
                    flippedCard2 = null;
                    isProcessing = false;
                } else {
                    // 匹配失败:延迟1秒后把两张卡片翻回去
                    PauseTransition pause = new PauseTransition(Duration.seconds(1));
                    pause.setOnFinished(e -> {
                        // 把按钮换回背面图片
                        flippedButton1.setGraphic(backCardView);
                        flippedButton2.setGraphic(backCardView);
                        // 清空记录
                        flippedButton1 = null;
                        flippedButton2 = null;
                        flippedCard1 = null;
                        flippedCard2 = null;
                        isProcessing = false;
                    });
                    pause.play();
                }
            }
        }
    }
}

关键部分解释

  1. Card类的作用:把卡片的图片和配对数值绑定在一起,后续点击时直接拿数值对比,不用额外处理图片名,简单清晰。
  2. 按钮列表和UserData:用ArrayList<Button>管理所有卡片按钮,避免重复写四个按钮的代码;用setUserData()把按钮和对应的Card对象绑定,点击时直接取出,不用再去列表里找。
  3. 配对逻辑:
    • 用两个变量记录当前翻转的两张卡片,防止同时翻多张
    • 匹配成功就禁用按钮,避免重复点击
    • 匹配失败用PauseTransition延迟1秒翻回去,这样你能看到两张卡片的正面,不会立刻翻回去
  4. 防止重复操作:用isProcessing标记是否正在处理配对,这时候点击其他卡片不会有反应,避免界面混乱。

注意事项

  • 确保你的图片文件(backCard.jpg、2_Clubs.jpg等)和项目的根目录在同一个文件夹里,或者修改图片路径为正确的位置。
  • 如果要扩展更多卡片,只需要在cardList里添加更多Card对象就行,按钮会自动创建,不用改其他代码~

内容的提问来源于stack exchange,提问作者Dylan Dugan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 19:47:52