How to add pictures to memory game? I made it like a number game and now want to add pictures so that players can play a picture flip memory game. I have attached the code, and Board.java is somewhere changes are needed. I am really stuck on this one, any help will be appreciated.
Code.java
import javax.swing.JButton;
public class Card extends JButton{
private String id;
private boolean matched = false;
public void setId(String val){
this.id = val;
}
public String getId(){
return this.id;
}
public void setMatched(boolean matched){
this.matched = matched;
}
public boolean getMatched(){
return this.matched;
}
}
Game.java
import java.awt.Dimension;
import javax.swing.JFrame;
public class Game{
public static void main(String[] args){
Board b = new Board();
b.setPreferredSize(new Dimension(500,500)); //need to use this instead of setSize
b.setLocation(500, 250);
b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.pack();
b.setVisible(true);
}
}
Board.java
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
public class Board extends JFrame{
private List<Card> cards;
private Card selectedCard;
private Card c1;
private Card c2;
private Timer t;
static String fruits[] = {"pear.jpg", "peach.jpg", "pineapple.jpg", "/apple.jpg",
"avocado.jpg", "/greenapple.jpg"};
static String files[] = fruits;
public Board(){
int pairs = 14;
List<Card> cardsList = new ArrayList<Card>();
List<String> cardVals = new ArrayList<String>();
for (int i = 0; i < pairs; i ){
cardVals.add(i, fruits[i]);
cardVals.add(i, fruits[i]);
}
Collections.shuffle(cardVals);
for (String val : cardVals){
Card c = new Card();
c.setId(val);
c.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
selectedCard = c;
doTurn();
}
});
cardsList.add(c);
}
this.cards = cardsList;
//set up the timer
t = new Timer(750, new ActionListener(){
public void actionPerformed(ActionEvent ae){
checkCards();
}
});
t.setRepeats(false);
//set up the board itself
Container pane = getContentPane();
pane.setLayout(new GridLayout(4, 5));
for (Card c : cards){
pane.add(c);
}
}
public void doTurn(){
if (c1 == null && c2 == null){
c1 = selectedCard;
c1.setText(String.valueOf(c1.getId()));
}
if (c1 != null && c1 != selectedCard && c2 == null){
c2 = selectedCard;
c2.setText(String.valueOf(c2.getId()));
t.start();
}
}
public void checkCards(){
if (c1.getId() == c2.getId()){//match condition
c1.setEnabled(false); //disables the button
c2.setEnabled(false);
c1.setMatched(true); //flags the button as having been matched
c2.setMatched(true);
if (this.isGameWon()){
JOptionPane.showMessageDialog(this, "You win!");
System.exit(0);
}
}
else{
c1.setText(""); //'hides' text
c2.setText("");
}
c1 = null; //reset c1 and c2
c2 = null;
}
public boolean isGameWon(){
for(Card c: this.cards){
if (c.getMatched() == false){
return false;
}
}
return true;
}
}
CodePudding user response:
First line in method checkCards
is:
if (c1.getId() == c2.getId()){//match condition
It should be:
if (c1.getId().equals(c2.getId())){
Refer to How do I compare strings in Java?
You don't need a class that extends JButton. A Component has a name so use methods setName(String)
and getName()
rather than adding an ID field. Also, a JComponent supports custom properties so make the matched
flag a custom property.
The first for
loop, in the constructor of class Board
, throws ArrayIndexOutOfBoundsException
since you only have six images in array fruits
. I assume that you want each image to appear on two different cards. The loop should be:
for (int i = 0; i < fruits.length; i ){
cardVals.add(fruits[i]);
cardVals.add(fruits[i]);
}
Refer to the javadoc for methods add(E)
and add(int, E)
. Method add(E)
simply adds to the end of the list.
So now you want the JButton
s to show an icon rather than text. So first you need to create the icons. Initially, none of the JButton
s has an icon. Then, when the user clicks on a JButton
you want to add an appropriate icon to it. You also need to be able to remove the icon. You can do this via method setIcon
. If the method parameter is null, the icon is removed and when the parameter is not null, an icon is added to the JButton
.
I use a Map
to associate a JButton
with its icon. The Map
key is the ID attribute in your Card
class and the Map
value is the actual icon.
To keep things simple, I added all the icon files to the same package as your Board
class. Refer to How to Use Icons for more details about creating icons in Swing.
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Collections;
import java.util.HashMap;
public class Board extends JFrame {
private static final String MATCHED = "MATCHED";
private static final Map<String, Icon> ICONS;
private List<JButton> cards;
private JButton selectedCard;
private JButton c1;
private JButton c2;
private Timer t;
static String fruits[] = {"pear.png",
"peach.png",
"pineapple.png",
"apple.png",
"avocado.png",
"greenapple.png"};
static String files[] = fruits;
static {
ICONS = new HashMap<>(fruits.length);
Class<?> theClass = Board.class;
for (int i = 0; i < fruits.length; i ) {
ICONS.put(fruits[i], new ImageIcon(theClass.getResource(fruits[i])));
}
}
public Board() {
List<JButton> cardsList = new ArrayList<JButton>();
List<String> cardVals = new ArrayList<String>();
for (int i = 0; i < fruits.length; i ){
cardVals.add(fruits[i]);
cardVals.add(fruits[i]);
}
Collections.shuffle(cardVals);
for (String val : cardVals){
JButton c = new JButton();
c.setName(val);
c.putClientProperty(MATCHED, Boolean.FALSE);
c.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
selectedCard = c;
doTurn();
}
});
cardsList.add(c);
}
this.cards = cardsList;
//set up the timer
t = new Timer(750, new ActionListener(){
public void actionPerformed(ActionEvent ae){
checkCards();
}
});
t.setRepeats(false);
//set up the board itself
Container pane = getContentPane();
pane.setLayout(new GridLayout(4, 5));
for (JButton c : cards){
pane.add(c);
}
}
public void doTurn(){
if (c1 == null && c2 == null){
c1 = selectedCard;
c1.setIcon(ICONS.get(c1.getName()));
}
if (c1 != null && c1 != selectedCard && c2 == null){
c2 = selectedCard;
c2.setIcon(ICONS.get(c2.getName()));
t.start();
}
}
public void checkCards(){
if (c1.getName().equals(c2.getName())) { //match condition
c1.setEnabled(false); //disables the button
c2.setEnabled(false);
c1.putClientProperty(MATCHED, Boolean.TRUE); //flags the button as having been matched
c2.putClientProperty(MATCHED, Boolean.TRUE);
if (this.isGameWon()){
JOptionPane.showMessageDialog(this, "You win!");
System.exit(0);
}
}
else{
c1.setIcon(null); //'hides' text
c2.setIcon(null);
}
c1 = null; //reset c1 and c2
c2 = null;
}
public boolean isGameWon() {
for (JButton c : cards) {
if (c.getClientProperty(MATCHED) == Boolean.FALSE) {
return false;
}
}
return true;
}
public static void main(String[] args) {
Board b = new Board();
b.setPreferredSize(new Dimension(500,500)); //need to use this instead of setSize
b.setLocation(500, 250);
b.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
b.pack();
b.setVisible(true);
}
}
Note that I downloaded my own icons from the Internet, hence the names don't exactly match your names. Also, I placed all the PNG files in the same directory as file Board.class
(i.e. the file created when compiling the Java source code).