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(); } } } } }
关键部分解释
- Card类的作用:把卡片的图片和配对数值绑定在一起,后续点击时直接拿数值对比,不用额外处理图片名,简单清晰。
- 按钮列表和UserData:用
ArrayList<Button>管理所有卡片按钮,避免重复写四个按钮的代码;用setUserData()把按钮和对应的Card对象绑定,点击时直接取出,不用再去列表里找。 - 配对逻辑:
- 用两个变量记录当前翻转的两张卡片,防止同时翻多张
- 匹配成功就禁用按钮,避免重复点击
- 匹配失败用
PauseTransition延迟1秒翻回去,这样你能看到两张卡片的正面,不会立刻翻回去
- 防止重复操作:用
isProcessing标记是否正在处理配对,这时候点击其他卡片不会有反应,避免界面混乱。
注意事项
- 确保你的图片文件(
backCard.jpg、2_Clubs.jpg等)和项目的根目录在同一个文件夹里,或者修改图片路径为正确的位置。 - 如果要扩展更多卡片,只需要在
cardList里添加更多Card对象就行,按钮会自动创建,不用改其他代码~
内容的提问来源于stack exchange,提问作者Dylan Dugan
相关产品推荐
相关产品推荐

