Jump to content

Memory game - help with Timer and Mouse/ActionListener

- - - - -

  • Please log in to reply
3 replies to this topic

#1
evilmonkey2k5

evilmonkey2k5

    Newbie

  • Members
  • Pip
  • 3 posts
Hi

I'm working on a Java GUI memory game where you're supposed to find two of a kind. Basically what I want is that when you click on an image (an ImageIcon inside a JLabel), I want it to change into another image, show that for about 1 second and then swap back to the original image. I can get it to change into another image by using the setIcon()-method, but not to change back. Would really appreciate if anyone could go over the code and see what's wrong/what needs to be fixed.

public class ButtonPanel extends JPanel implements ActionListener, MouseListener {

	private GameFrame gameFrame;

	private JButton exit, newgame;

	private MemoryPanel memoryPanel;

	private MemoryDeck memoryDeck1, memoryDeck2;

	private URL url;

	private JLabel l1;

	private ImageIcon imgback;

	Timer visibleTimer = new Timer(1000, this);


	public ButtonPanel(GameFrame gameFrame, MemoryPanel memoryPanel) {

		this.gameFrame = gameFrame;

		this.memoryPanel = memoryPanel;


		newgame = new JButton("New game");

		exit = new JButton("Exit");


		newgame.addActionListener(this);

		exit.addActionListener(this);


		add(newgame);

		add(exit);

	}


	public void newgame() {

		memoryPanel.removeAll();

		memoryPanel.repaint();


		memoryDeck1 = new MemoryDeck();

		memoryDeck1.shuffle();

		memoryDeck2 = new MemoryDeck();

		memoryDeck2.shuffle();


		url = getClass().getResource("/Images/memory/memoryback.gif");

		imgback = new ImageIcon(url);

		l1 = new JLabel(imgback);

		l1.addMouseListener(this);


		memoryPanel.add(l1);

		memoryPanel.validate();

	}


	public void actionPerformed(ActionEvent e) {

		repaint();

		if (e.getSource() == exit)

			gameFrame.setMenuPanelActive();

		if (e.getSource() == newgame)

			newgame();

	}


	public void mouseClicked(MouseEvent e) 

	{

		if (e.getSource() == l1) {

			visibleTimer.start();

			visibleTimer.setRepeats(false);

			l1.setIcon(memoryDeck1.getCard(0).getImage());

		}

	}


	public void mouseEntered(MouseEvent e) { }

	public void mouseExited(MouseEvent e) { }

	public void mousePressed(MouseEvent e) { }

	public void mouseReleased(MouseEvent e) { }

}


#2
ZekeDragon

ZekeDragon

    Writes binary right handed and hex left handed

  • Moderators
  • 2,103 posts
First, let me dispense with some advice, because all in all your code is pretty good, just a couple of your name's were very distracting.

	private JButton exit, newgame;
	public void newgame() {
You have a method named newgame and an object named newgame. That's frustrating.
	private JLabel l1;
Many programming fonts, by their nature, display 'l' and '1' as unambiguously as possible, but not all fonts do. Be wary of these things when you write code, even if you don't plan on using it much, because it could end up being transmitted and read, and that display won't have the same font you're using to code. This code snippet:
Posted Image
looks an awful lot like if (e.getSource() == 11), which is cryptic.

Anyway, to the main topic...

You're not really utilizing your timer correctly. I wouldn't use the Swing timer either, this is much easier to implement with the java.util.Timer. Using java.util.Timer, all you'd have to do with visibleTimer is schedule a TimerTask that would change l1's icon back.

    if (e.getSource() == l1)

    {

        l1.setIcon(memoryDeck1.getCard(0).getImage());

        visibleTimer.schedule(new TimerTask() {

            public void run()

            {

                l1.setIcon(imgback);

            }

        });

    }

Also, I'd use a customized AbstractButton subclass instead of JLabel to be the game buttons.
Wow I changed my sig!

#3
evilmonkey2k5

evilmonkey2k5

    Newbie

  • Members
  • Pip
  • 3 posts
Thanks for the advices. I'll try to make my code abit clearer in the future :)

I added your code, made the Timer a java.util.Timer instead and set up a 1000 ms delay, and it works! Thank you very much for the help! I haven't worked with AbstractButtons before, but I'm going over it now and it does look like a much better option. Again, thanks alot :thumbup:

#4
evilmonkey2k5

evilmonkey2k5

    Newbie

  • Members
  • Pip
  • 3 posts
Didn't take long 'till I ran into another problem again. The method for checking if the two images (JLabels) are the same is bugging up. Sometimes it works (sets the two images visible at all times), but other times it sets two nonidentical images visible, rather than changing both the images back to original. Other times it just randomly sets one image visible. It's probably in the actionPerformed-method something needs to be changed.


package Memory;


import javax.swing.*;

import javax.swing.Timer;

import java.awt.*;

import java.awt.event.*;

import Menu.*;

import java.net.*;

import java.util.*;


public class ButtonPanel extends JPanel implements ActionListener, MouseListener {

	private GameFrame gameFrame;

	private MemoryPanel memoryPanel;

	private MemoryDeck memoryDeck, memoryDeckBack;

	private URL url;

	private JButton exit, newgame;

	private JLabel[] labeltable;

	private ImageIcon imgback;

	private final int IMG_DELAY = 1000; 

	private int num, numPressed, num2;

	private boolean areAlike = false;

	Timer showTimer;


	public ButtonPanel(GameFrame gameFrame, MemoryPanel memoryPanel) {

		this.gameFrame = gameFrame;

		this.memoryPanel = memoryPanel;

		

		showTimer = new Timer(IMG_DELAY, this);

		newgame = new JButton("New game");

		exit = new JButton("Exit");

		labeltable = new JLabel[16];

		num = 0;


		newgame.addActionListener(this);

		exit.addActionListener(this);


		add(newgame);

		add(exit);

	}


	public void doNewgame() {

		memoryPanel.removeAll();

		memoryPanel.repaint();


		memoryDeck = new MemoryDeck();

		memoryDeck.shuffle();


		url = getClass().getResource("/Images/memory/memoryback.gif");

		imgback = new ImageIcon(url);

		memoryDeckBack = new MemoryDeck();

		for (int i = 0; i < 16; i++) {

			labeltable[i] = new JLabel(memoryDeckBack.getCardBack(i).getImage());

			labeltable[i].addMouseListener(this);

			memoryPanel.add(labeltable[i]);

			memoryPanel.validate();

		}

	}



	public void actionPerformed(ActionEvent e) {

		repaint();

		if (e.getSource() == exit)

			gameFrame.setMenuPanelActive();

		if (e.getSource() == newgame)

			doNewgame();

		if (e.getSource() == showTimer) {

			System.out.println(num2);

			numPressed++;

			if (numPressed != 2)	//If only one picture is chosen

				num2 = num;			//sets the value of num2 to num, which is defined in mouseClicked().


			if (numPressed == 2) 

			{

				if (memoryDeck.getCardFront(num).getType() == memoryDeck.getCardFront(num2).getType()) {

					//checks if the two chosen cards are the same by checking their value.

					areAlike = true;

				}

				if (areAlike == false) {

					labeltable[num].setIcon(imgback);

					labeltable[num2].setIcon(imgback);

				}

				num2 = 0;

				numPressed = 0;

				areAlike = false;

			}

		}

	}


	public void mouseClicked(MouseEvent e) 

	{

		for (int i=0; i<16; i++) {

			if (e.getSource() == labeltable[i]) {

				labeltable[i].setIcon(memoryDeck.getCardFront(i).getImage());

				showTimer.start();

				showTimer.setRepeats(false);

				num = i; 		//num is set to the i-th label in the array and is then being used by actionPerformed 

								//on showTimer to set the value.

			}

		}

	}


	public void mouseEntered(MouseEvent e) { }

	public void mouseExited(MouseEvent e) { }

	public void mousePressed(MouseEvent e) { }

	public void mouseReleased(MouseEvent e) { }

}


I'll throw in the MemoryDeck-class as well so you'll know how the array of images are made.

p
ackage Memory;


public class MemoryDeck {

	private MemoryImage[] deckfront, deckback;

	private int k = 0;


	public MemoryDeck() {

		deckfront = new MemoryImage[16];

		deckback = new MemoryImage[16];

		for (int i=0; i<16; i+=2) {

			deckfront[i] = new MemoryImage(k+1);

			deckfront[i+1] = new MemoryImage(k+1);

			k++;

		}

		for (int i=0; i<16; i++) {

			deckback[i] = new MemoryImage();

		}

	}


	public void shuffle() {

		int pick, pick2;

		for (int i=0; i<500; i++) {

			pick = (int)(Math.random()*15);

			pick2 = (int)(Math.random()*15);

			MemoryImage swap = deckfront[pick];

			deckfront[pick] = deckfront[pick2];

			deckfront[pick2] = swap;

		}

	}


	public MemoryImage getCardFront(int kortnr) {

		return deckfront[kortnr];

	}

	

	public MemoryImage getCardBack (int kortnr) {

		return deckback[kortnr];

	}

}

The deckfront creates an array of 2 x 8 individual pictures and the deckback creates an array with 16 places which are all filled with cards facing down.
I could throw in the MemoryImage-class as well, but I'll explain instead. The first constructor takes an int as a parameter to indicate which picture to make (as I've named mine memory1.gif, memory2.gif etc.) and return it as an ImageIcon. The other constructor doesn't take any parameter and just makes an ImageIcon of a card facing down.
Hope I didn't leave anything out. Just ask if there's something unclear with the code and I'll try to explain.




2 user(s) are reading this topic

0 members, 2 guests, 0 anonymous users