You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

记忆匹配游戏开发疑问:匹配成功后如何禁用JToggleButton

解决记忆匹配游戏中匹配成功后无法禁用JToggleButton的问题

嘿,我帮你梳理下代码里的关键问题,然后给出修复方案,让你的游戏能正常处理匹配成功后的按钮禁用逻辑:

核心问题分析

  • 错误的实例引用:你在Clicked监听器里新建了一个start matching = new start();,这个新实例和界面上显示的那个完全没关系,所以你修改matching.DisplayCards[posI][posJ]的时候,根本影响不到真实界面上的按钮。
  • 匹配成功后未处理第一张按钮:现在你只禁用了当前点击的按钮,但没对第一次选中的那张做同样的禁用操作,也没重置状态标记,导致后续逻辑混乱。
  • 忘记调用洗牌方法:你的Shuffle类里有洗牌逻辑,但初始化界面时没调用shuffle.random(),卡片始终是固定重复的排列,不会随机打乱。
  • 状态逻辑不完整:匹配成功后没重置statefirst这些变量,后续点击会出现逻辑错误。

修复后的完整代码

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

火山引擎 最新活动