-2

I'm making a program in java to emulate a basic deck of cards; no specific game in mind, just a good old deck of cards that you can move around and flip over freely (of course, with the limit of 52 total cards). Here is my current code:

package cards;
import java.awt.Color;
import java.awt.Graphics;
import java.util.List;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class DeckOfCards extends JPanel{
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    static final int SIZE = 500;
    public static String side = "back";
    static final int xSize = 73;
    static final int ySize = 98;
    static int x = SIZE - xSize;
    static int y = 0;
    static int i, j = 0;
    static int inDeck = 52;
    public boolean flipped = false;
    static final DeckOfCards m = new DeckOfCards();
    static final Color rgb = new Color(0, 180, 10);
    static final JFrame frame = new JFrame();
    static List<Integer> yList = new ArrayList<Integer>();
    static List<Integer> xList = new ArrayList<Integer>();
    Random random = new Random();
    int randX = random.nextInt(13) * xSize; 
    int randY = random.nextInt(4) * ySize;
    int xRand = randX;
    int yRand = randY;
    public static void main(String[] args){
        frame.setTitle("Virtual Cards");
        frame.add(m);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(SIZE, SIZE);
        frame.setResizable(false);
        m.setBackground(rgb);
        frame.setVisible(true);
    }
    public void mouseClick(){
        addMouseListener(new MouseAdapter(){
            @Override
            public void mouseClicked(MouseEvent e){
                if(((e.getX() >= x && e.getX() <= (x + xSize)) && (e.getY() >= y && e.getY() <= (y + ySize))) && (flipped == false)){
                    flipped = true;
                    side = "front";
                }else if(((e.getX() >= x && e.getX() <= (x + xSize)) && (e.getY() >= y && e.getY() <= (y + ySize))) && (flipped == true)){
                    flipped = false;
                    side = "back";
                }else if((e.getX() >= SIZE - xSize && e.getX() <= SIZE) && (e.getY() >= 0 && e.getY() <= SIZE - (SIZE - ySize)) && inDeck > 0){
                    randCardFace(random);
                    inDeck--;
                    side = "back";
                    x = SIZE - xSize;
                    y = 0;
                }
            }

        });
    }
    public void mouseMove(){
        addMouseMotionListener(new MouseMotionAdapter(){
            @Override
            public void mouseDragged(MouseEvent e){
                if(((e.getX() >= x && e.getX() <= (x + xSize)) && (e.getY() >= y && e.getY() <= (y + ySize)))){
                    x = e.getX() - (xSize / 2);
                    y = e.getY() - (ySize / 2); 
                }
            }
        });
    }
    public DeckOfCards(){
        mouseClick();
        mouseMove();
    }
    public void randCardFace(Random random){
            randX = random.nextInt(13) * xSize;
            randY = random.nextInt(4) * ySize;
    }
    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        paint(g);
    }
    public void paint(Graphics g){
        try{
            if(inDeck > 0){
                g.drawImage(ImageIO.read(getClass().getResource("images/deck.png")), SIZE - xSize, 0, null, null);
            }
            BufferedImage image = ImageIO.read(getClass().getResource("images/"+side+".png"));
            if(side != "back"){
                image = image.getSubimage(randX, randY, xSize, ySize);
            }
            g.drawImage(image, x, y, xSize, ySize, null, null);
        }catch(IOException e){
            e.printStackTrace();
        }
        m.repaint();
    }
}

However, this program will only let me have one card out at a time until I click on the deck in the top right corner and reshuffle(redefine the area of the image to be read with a random number generator). What I would like to do is be able to have any amount of cards from 0 and 52 out at any given time by clicking the deck without creating 51 new variables for the other cards(fyi I have written out some of the code for what I want, but so far it's done nothing but cause problems so I decided to start from scratch and ask the experts what I should do).

edit:

just realized after asking this, this is a slightly older code than I wanted to post, and has probably has plenty of other problems as well. Please ignore those, as they are already fixed.

dakatk
  • 99
  • 1
  • 1
  • 13
  • 1
    Your program so far is grossly over-using static variables, and not using any object-oriented principles whatsoever. I think that you have the card before the horse: you're worrying about graphic representation without yet creating a decent object oriented framework for your program. Start with your object concepts *first*, then worry about the GUI later. – Hovercraft Full Of Eels Nov 28 '13 at 02:25
  • `"ust realized after asking this, this is a slightly older code than I wanted to post, and has probably has plenty of other problems as well. Please ignore those, as they are already fixed."` -- please don't confuse us then with old error-filled code. Please correct this. – Hovercraft Full Of Eels Nov 28 '13 at 02:27
  • read my edit. I know this version has over-used static variables and whatnot, but I can't post a later(fixed) version because I back tracked with this code by undo-ing it and then saving and quitting. Honestly though, when I did fix those things, it created even more problems with the execution of the program. – dakatk Nov 28 '13 at 02:30
  • 1
    For better help sooner, post an [SSCCE](http://sscce.org/) (of the *actual* code used). One way to get image(s) for an example is to hot-link to the images seen in [this answer](http://stackoverflow.com/a/19209651/418556). – Andrew Thompson Nov 28 '13 at 02:30
  • Yes, first define a model. At least a class that represents a Card. Then explain better what you want to do. What is the problem with having 52 variables? You don't want 52 variables or you just want an array with 52 positions, each being a card? – Ric Jafe Nov 28 '13 at 02:30
  • Tip: Add @HovercraftFullOfEels (or whoever - the `@` is important) to ensure they are **notified** of a new message. – Andrew Thompson Nov 28 '13 at 02:32
  • 1
    `"Honestly though, when I did fix those things, it created even more problems with the execution of the program."` -- it doesn't matter. You should scrap this code as it's not anywhere near what you want as the basis for your program. Just scrap this question and this code, and start from first principles. – Hovercraft Full Of Eels Nov 28 '13 at 02:32
  • This question appears to be off-topic because the autghor realized that he posted the wrong code. – Devolus Nov 28 '13 at 08:19

2 Answers2

3

You posted your code with lots of problems, so allow me to give you some advice over it. If it is not the correct code, then please correct it:

  • You should override a JPanel's paintComponent method not its paint method, not unless you need to change the behavior of how a component's children and borders paint themselves (you don't).
  • You should never read in images within paint or paintComponent as this will slow your rendering and thus program responsiveness to a crawl.
  • You should never call repaint() from within paint or paintComponent.
  • You are calling paint from within paintComponent and this risks a terrible recursion since paint calls paintComponent. Never do this.
  • Your code over uses static. This will prevent it from being extensible and will limit its modifiability.
  • You're building a GUI without first creating a decent model. Card programs have well described common models. These including the use enums for Java versions with an enum for Suit and an enum for Rank. Get the abstract concept and classes for Card, Deck, Player, Game down first before working on their image counterparts.

Links to some other answers and code of mine regarding card games:

Community
  • 1
  • 1
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
2

There are two basic approaches, the both kind of follow the same basic concept...

Generate a list of images and paint them...

You Could...

Create a custom component which is singularly responsible for painting a single card. The benefit of this is that it's generally easy to manage and uses what is already available.

The draw back is, you're going to need take charge the the layout management (a little).

You would start with a LayredPane, which will allow you to push cards up and down (virtually) as well as allow them to be placed where you want them.

Personally, I would create a single MouseListener/MouseMotionListener and register it to each of the "Card Panels", this will allow to easily control the cards with relation to the LayeredPane (moving them to the top when they are clicked for example)

You Could...

The other choice would be to load each of the card images and place them into List. Then basically, you would then simply paint them with in the paintComponent method by simply iterating through the list.

The problem is, you suddenly become responsible for the entire management of the z-order and checking what is clicked.

Customising the painting of the images (such as adding borders) becomes a little cumbersome, as you need to do this for each image and decide when. This would be easier if they were a custom component

Feedback

  • Beware of the over use of static variables, this can quickly lead you into problem areas with trying to do determine what is actually being referenced
  • Don't call paint from paintComponent. paint actually calls paintComponent itself, which could produce a stack overflow errors
  • Don't call any method from within a paintXxx method that might call repaint, because of the way painting works, this will simply cause the EDT to simply keep painting your component, which will eventually consume your CPU...

Take a closer look at Performing Custom Painting and Painting in AWT and Swing for more details

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thanks for the advice. I've never heard that it's bad to call `paint` within `paintComponent`, that's just always how I've done it's worked fine. However I have changed that in this program and it works the same, so I guess that I'll keep that in mind for future endeavors. – dakatk Nov 28 '13 at 04:01
  • Basically, you fluked it. Because you don't call super.paint(g), it never calls paintComponent directly. But the normal paint chain starts with paint call paintComponent and a few other methods... – MadProgrammer Nov 28 '13 at 04:42