记忆游戏实现 [英] Memory Game implementation
问题描述
我已经开始玩一个非常基本的记忆游戏.
I have started on a really basic memory game.
private void tbtnCard3ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card3Logo.png")));
if(tbtnCard5.isSelected()){
score++;
lblScore.setText(""+score);
}
}
private void tbtnCard4ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card7EWaste.png")));
if(tbtnCard7.isSelected()){
score++;
lblScore.setText(""+score);
}
}
private void tbtnCard5ActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/Card3Logo.png")));
if(tbtnCard3.isSelected()){
score++;
lblScore.setText(""+score);
}
}
使用 Java Swing,我已经用我需要的图像设置了图标.在底部,我有一个按钮调用 start 以便首先显示所有按钮,直到按下 start btn.
Using Java Swing, I have set the icons with the images I need. Over at the bottom I have a button call start so that at first all buttons are shown until start btn is pressed.
private void btnStartActionPerformed(java.awt.event.ActionEvent evt) {
tbtnCard1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard2.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard4.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard5.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard6.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard7.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard8.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard9.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard10.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard11.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard12.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard13.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard14.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard15.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard16.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard17.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard18.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard19.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
tbtnCard20.setIcon(new javax.swing.ImageIcon(getClass().getResource("/BlankImage.png")));
}
我唯一的问题是在玩家从一组 2 张中选错了一张牌后,两张牌都应该回到空白图像.我该怎么做?
My only question is after a player picks a wrong card from a set of 2,both cards should go back to the blank image. How would I go about that?
推荐答案
以下是一个简单记忆游戏的示例逻辑:
Here is a sample logic for a simple memory game:
- 使用
JToggleButton
s 来表示单元格. - 将每个按钮的图标用于隐藏状态,以及选择图标,用于显示状态.
- 首先启用所有
JToggleButton
并且未选中(隐藏 状态). - 当用户选择一个
JToggleButton
时,它会自动更改为 shown 状态. - 向所有
JToggleButton
添加相同的侦听器,以便随时跟踪最后两个选定的按钮.如果找到匹配项,则您可以禁用匹配按钮,如果未找到匹配项,则只需取消选择它们即可.
- Use
JToggleButton
s to represent the cells. - Use the icon of each button for the hidden state, and the selection icon for the shown state.
- Start with all
JToggleButton
s enabled and not selected (hidden state). - When the user selects a
JToggleButton
it changes to shown state automatically. - Add the same listener to all
JToggleButton
s which will track the last two selected buttons at any time. If a match is found then you can disable the matching buttons, if no match is found then simply unselect them.
为了在下面的演示代码中简单起见,我为上述所有目的使用了一个自定义的 Icon
实现,它只是绘制了一个某种颜色的圆角矩形.颜色用于将按钮标识为彼此匹配,即相同颜色的按钮表示选择了匹配.我只是在 隐藏 状态下为每个按钮使用了一个白色的圆角矩形,而在 显示 状态下使用了随机颜色.
For simplicity in the following demonstrating code, I used a custom Icon
implementation for all above purposes which just draws a rounded rectangle of some color. The color is used to identify the buttons as matching with each other, ie same colored buttons means a match was selected. I just used a rounded rectangle of white color for each button at the hidden state, while random colors for the shown state.
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Random;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Main {
private static class RoundRectIcon implements Icon {
private final Color c;
public RoundRectIcon(final Color c) {
this.c = Objects.requireNonNull(c);
}
public Color getColor() {
return c;
}
@Override
public void paintIcon(final Component c,
final Graphics g,
final int x,
final int y) {
g.setColor(this.c);
g.fillRoundRect(x, y, getIconWidth() - 1, getIconHeight() - 1, getIconWidth() / 2, getIconHeight() / 2);
}
@Override
public int getIconWidth() {
return 50;
}
@Override
public int getIconHeight() {
return 50;
}
}
private static class MemoryGameActionListener implements ActionListener {
private final Timer revertTimer;
private JToggleButton button1, button2;
private int pairsCount;
public MemoryGameActionListener(final int delay,
final int pairsCount) {
if (pairsCount <= 0)
throw new IllegalArgumentException("Non positive pairsCount.");
this.pairsCount = pairsCount;
button1 = button2 = null;
revertTimer = new Timer(delay, this);
revertTimer.setRepeats(false);
}
@Override
public void actionPerformed(final ActionEvent e) {
revertTimer.stop();
final Object source = e.getSource();
if (source instanceof JToggleButton) {
final JToggleButton button = (JToggleButton) source;
if (button.isSelected()) {
if (button1 == null) //If we are in an initial state:
button1 = button; //Store the first clicked button.
else if (button2 == null) { //Else we have stored the first button, so store and check the second one...
button2 = button;
final RoundRectIcon icon1 = (RoundRectIcon) button1.getSelectedIcon(),
icon2 = (RoundRectIcon) button2.getSelectedIcon();
if (Objects.equals(icon1.getColor(), icon2.getColor())) {
System.out.println("Pair of " + icon1.getColor() + " found!");
button1.setEnabled(false); //Don't let the user able to click it again.
button2.setEnabled(false); //Don't let the user able to click it again.
button1 = button2 = null; //A cycle is complete.
if (--pairsCount == 0)
JOptionPane.showMessageDialog(null, "You found every pair.", "You win", JOptionPane.INFORMATION_MESSAGE);
}
else {
System.out.println("Invalid match of " + icon1.getColor() + ", and " + icon2.getColor() + '.');
revertTimer.start(); //This timer will unselect the selected button pair after a delay.
}
}
else { //Else both buttons are stored, so this is the third one, so just ignore the previous buttons (if they did not match):
if (button1.isEnabled())
button1.setSelected(false);
if (button2.isEnabled())
button2.setSelected(false);
button1 = button; //Suppose now that the third clicked button is the first one.
button2 = null;
}
}
else { //Else the user unselected a button, so reset:
if (button1 != null) {
button1.setSelected(false);
button1 = null;
}
if (button2 != null) {
button2.setSelected(false);
button2 = null;
}
}
}
else if (source == revertTimer) { //If a pair was found previously but it didn't match up, then reset:
button1.setSelected(false);
button2.setSelected(false);
button1 = button2 = null;
}
else
System.err.println("Unknown source " + source); //This should never happen.
}
}
private static Color randomColor(final Random random) {
final byte[] components = new byte[3];
random.nextBytes(components);
return new Color(components[0] & 0xFF, components[1] & 0xFF, components[2] & 0xFF);
}
private static HashSet<Color> randomUniqueColors(final int count) {
final Random random = new Random();
final HashSet<Color> colors = new HashSet<>(count);
while (colors.size() < count) //If we produce the same color inside the loop, then 'colors.size()' will not increment.
colors.add(randomColor(random));
return colors;
}
private static JToggleButton createStandardToggleButton(final Color color,
final MemoryGameActionListener listener) {
final JToggleButton toggle = new JToggleButton(new RoundRectIcon(Color.WHITE)); //Default (ie enabled + unselected) icon is just a white round rect.
toggle.setSelectedIcon(new RoundRectIcon(color));
toggle.setDisabledIcon(toggle.getSelectedIcon());
toggle.setDisabledSelectedIcon(toggle.getSelectedIcon());
toggle.addActionListener(listener);
return toggle;
}
private static void createAndShowGUI() {
final int rows = 4, cols = 4, delay = 1000;
final int totalButtons = rows * cols; //The total number of buttons must be a multiple of 2 (because we use pairs of buttons).
final int totalPairs = totalButtons / 2;
final MemoryGameActionListener listener = new MemoryGameActionListener(delay, totalPairs);
final JPanel grid = new JPanel(new GridLayout(0, cols, 5, 5));
final ArrayList<JToggleButton> buttons = new ArrayList<>(totalButtons);
randomUniqueColors(totalPairs).forEach(color -> {
//Add the matching buttons to the list...
buttons.add(createStandardToggleButton(color, listener));
buttons.add(createStandardToggleButton(color, listener));
});
Collections.shuffle(buttons);
buttons.forEach(button -> grid.add(button));
final JFrame frame = new JFrame("Memory game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(grid);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(Main::createAndShowGUI);
}
}
我首先生成所需颜色数量的Set
,然后为每种颜色创建两个按钮,然后将它们打乱,最后将它们添加到JPanel
的JPanel
>GridLayout.
I first generate a Set
of the desired number of colors, then create two buttons for each color, then shuffle them and finally add them to a JPanel
of GridLayout
.
上面的示例代码可以很容易地调整以容纳您喜欢的任何Icon
,当然包括ImageIcon
s 和其他自定义的.
The above example code can be easily tweaked to hold any Icon
you like, which of course includes ImageIcon
s and other custom ones.
这篇关于记忆游戏实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!