记忆匹配游戏开发疑问:匹配成功后如何禁用JToggleButton
嘿,我帮你梳理下代码里的关键问题,然后给出修复方案,让你的游戏能正常处理匹配成功后的按钮禁用逻辑:
核心问题分析
- 错误的实例引用:你在
Clicked监听器里新建了一个start matching = new start();,这个新实例和界面上显示的那个完全没关系,所以你修改matching.DisplayCards[posI][posJ]的时候,根本影响不到真实界面上的按钮。 - 匹配成功后未处理第一张按钮:现在你只禁用了当前点击的按钮,但没对第一次选中的那张做同样的禁用操作,也没重置状态标记,导致后续逻辑混乱。
- 忘记调用洗牌方法:你的
Shuffle类里有洗牌逻辑,但初始化界面时没调用shuffle.random(),卡片始终是固定重复的排列,不会随机打乱。 - 状态逻辑不完整:匹配成功后没重置
state和first这些变量,后续点击会出现逻辑错误。
修复后的完整代码
1. 调整start类:传递自身引用给监听器,调用洗牌方法
import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; class start { JToggleButton DisplayCards[][] = new JToggleButton[4][4]; Shuffle shuffle = new Shuffle(); void main() { // 先调用洗牌方法,让卡片随机排列 shuffle.random(); JFrame frame = new JFrame("记忆匹配游戏"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 600); int y = 20; int x = 60; for (int i = 0; i < DisplayCards.length; ++i) { for (int j = 0; j < DisplayCards[i].length; ++j) { DisplayCards[i][j] = new JToggleButton("Click Me!"); DisplayCards[i][j].setBounds(x, y, 90, 126); y = y + 135; if (y >= 540) { y = 20; x = x + 120; } frame.add(DisplayCards[i][j]); // 把当前start实例传递给监听器,这样能操作界面上的真实按钮 DisplayCards[i][j].addActionListener(new Clicked(i, j, shuffle, this)); } } frame.setLayout(null); frame.setVisible(true); } public static void main(String[] args) { start start = new start(); start.main(); } }
2. 修正Clicked监听器:使用正确的界面实例,完善匹配逻辑
class Clicked implements ActionListener { String first; // 保存界面的真实start实例,不再新建 start matching; boolean state = false; Shuffle shuffle; private int i; private int j; int posI; int posJ; // 构造方法接收界面的start实例 public Clicked(int i, int j, Shuffle shuffle, start matching) { this.i = i; this.j = j; this.shuffle = shuffle; this.matching = matching; } public void actionPerformed(ActionEvent e) { JToggleButton tBtn = (JToggleButton) e.getSource(); // 如果按钮已经禁用,直接返回,避免重复操作 if (!tBtn.isEnabled()) { return; } if (tBtn.isSelected()) { tBtn.setText(shuffle.cards[i][j]); if (!state) { // 第一次点击,记录卡片值和位置 first = shuffle.cards[i][j]; posI = i; posJ = j; System.out.println("第一次选中:" + first); state = true; } else { // 第二次点击,对比卡片值 if (first.equals(shuffle.cards[i][j])) { System.out.println("匹配成功!"); // 同时禁用当前按钮和第一次点击的按钮 tBtn.setEnabled(false); matching.DisplayCards[posI][posJ].setEnabled(false); // 重置状态,准备下一轮配对 state = false; first = null; } else { System.out.println("不匹配,翻转回去"); // 加个500ms延迟,让玩家能看清两张卡片 Timer timer = new Timer(500, new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { tBtn.setText("Click Me!"); tBtn.setSelected(false); matching.DisplayCards[posI][posJ].setText("Click Me!"); matching.DisplayCards[posI][posJ].setSelected(false); // 重置状态 state = false; first = null; } }); timer.setRepeats(false); timer.start(); } } } else { // 主动取消选中第一次点击的卡片时,重置状态 if (state && (posI == i && posJ == j)) { state = false; first = null; } tBtn.setText("Click Me!"); } } }
3. Shuffle类保持不变(洗牌逻辑是正常的)
class Shuffle { String[][] cards = { {"A", "B", "C", "D"}, {"E", "F", "G", "H"}, {"A", "B", "C", "D"}, {"E", "F", "G", "H"} }; public void random() { for (int i = 0; i < cards.length; i++) { for (int j = 0; j < cards[i].length; j++) { int i1 = (int) (Math.random() * cards.length); int j1 = (int) (Math.random() * cards[i].length); String temp = cards[i][j]; cards[i][j] = cards[i1][j1]; cards[i1][j1] = temp; } } } }
关键修复点说明
- 传递真实界面实例:监听器现在使用的是界面上实际存在的
start对象,操作DisplayCards数组时能直接影响到界面上的按钮。 - 匹配成功后禁用两张按钮:配对正确时,同时禁用当前按钮和第一次选中的按钮,确保它们不会被再次点击。
- 添加延迟翻转:不匹配时加入短暂延迟,让玩家有时间看清两张卡片的内容,提升游戏体验。
- 防重复操作判断:在方法开头检查按钮是否已禁用,避免无效的重复点击操作。
- 调用洗牌方法:初始化界面时调用
shuffle.random(),让卡片随机排列,符合记忆游戏的需求。
这样修改后,你的记忆匹配游戏就能正常处理匹配成功后的按钮禁用逻辑啦。
内容的提问来源于stack exchange,提问作者Joshua Saikali




